Fetch Download Links on FreeSound.org

Adds download links on freesound.org. Works with a button press, or automatically.

当前为 2024-04-23 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Fetch Download Links on FreeSound.org
// @namespace    Violentmonkey Scripts
// @version      1.0
// @description  Adds download links on freesound.org. Works with a button press, or automatically.
// @author       Jupiter Liar
// @license      CC BY
// @match        https://freesound.org/*
// @description  4/23/2024, 2:30:00 AM
// @grant        none
// ==/UserScript==

// Function to handle grabbing HTML from linked page and replacing Grab button
function grabHtmlAndReplaceButton(button) {
  button.textContent = "Fetching...";
    // Find the parent search result element
    const searchResult = button.closest('.bw-search__result');

    // Find the first <a> element within the search result if available
    var link;
    if (searchResult) {
        link = searchResult.querySelector('a');
    } else {
        // If searchResult is not found, traverse up the DOM tree until we find an ancestor containing .bw-player
        var ancestor = button.parentElement;
        while (ancestor && !(ancestor.querySelector('.bw-player') && ancestor.querySelector('a'))) {
            ancestor = ancestor.parentElement;
        }
        // Once we find the ancestor containing .bw-player, find the first <a> element within it
        if (ancestor) {
            link = ancestor.querySelector('a');
        }
    }

    // Check if a link is found
    if (link) {
        // Fetch the linked page
        fetch(link.href)
            .then(response => response.text())
            .then(html => {
                // Create a temporary element to hold the fetched HTML
                const tempElement = document.createElement('div');
                tempElement.innerHTML = html;
                // Find the element with class "sound-download-button"
                const soundDownloadButton = tempElement.querySelector('.sound-download-button');
                const sidebarDownloadButton = tempElement.querySelector('.bw-sound__sidebar .btn-primary');
                // Replace the Grab button with the sound-download-button element
                if (soundDownloadButton) {
                    // Replace the Grab button with the sound-download-button element
                    button.parentNode.replaceChild(soundDownloadButton, button);
                } else if (sidebarDownloadButton) {
                    button.parentNode.replaceChild(sidebarDownloadButton, button);
                } else {
                    console.log('No download button found on the linked page');
                    // Update the button text content if no download button is found
                    button.innerText = "No button found";
                }
            })
            .catch(error => {
                console.error('Error fetching linked page:', error);
                button.textContent = "Error fetching page";
            });
    } else {
        console.log('No link found in search result');
    }
}

// Function to create and append grab buttons
function createGrabButtons(parentElement, grabMode, additionalClass) {
    // If grabMode is true, insert grab buttons
    if (grabMode) {
        const grabberDiv = document.createElement('div');
        grabberDiv.classList.add('grabber');
        if (additionalClass) {
            grabberDiv.classList.add(additionalClass); // Add additional class if it exists
        }
        // grabberDiv.classList.add('in-row'); // Add in-row class
        // Create the Grab button
        const grabButton = document.createElement('button');
        grabButton.classList.add('grab-button');
        grabButton.textContent = 'Get download button';

        // Add event listener to the Grab button
        grabButton.addEventListener('click', function () {
            grabHtmlAndReplaceButton(this);
        });

        // Append the Grab button to the grabber div
        grabberDiv.appendChild(grabButton);

        // Append the grabber div to the parent element
        parentElement.appendChild(grabberDiv);
    }
}

function createInsertAllButton(topLevelElement) {
  // Create the container for "Insert all download buttons" button
        const insertAllContainer = document.createElement('div');
        insertAllContainer.classList.add('show-all-download-buttons');

        // Create the "Insert all download buttons" button
        const insertAllButton = document.createElement('button');
        insertAllButton.classList.add('btn-primary', 'w-100', 'insert-all-download-buttons');
        insertAllButton.textContent = 'Insert all download buttons';

        // Add event listener to the "Insert all download buttons" button
        insertAllButton.addEventListener('click', function () {
            clickAllGrabButtons();
        });

        // Append the button to the container
        insertAllContainer.appendChild(insertAllButton);

        // Insert the container before the very first search result
        topLevelElement.parentNode.insertBefore(insertAllContainer, topLevelElement);

        // Create the div for auto-insert option
        const autoInsertDiv = document.createElement('div');
        autoInsertDiv.classList.add('auto-insert-div');

        // Create the checkbox for auto-insert option
        const autoInsertCheckbox = document.createElement('input');
        autoInsertCheckbox.type = 'checkbox';
        autoInsertCheckbox.checked = localStorage.getItem('autoInsertCheckbox') === 'true'; // Check local storage for value

        // Add event listener to the auto-insert checkbox
        autoInsertCheckbox.addEventListener('change', handleAutoInsertChange);

        // Create the span for auto-insert option
        const autoInsertSpan = document.createElement('span');
        autoInsertSpan.textContent = 'Do this automatically';

        // Append checkbox and span to auto-insert div
        autoInsertDiv.appendChild(autoInsertCheckbox);
        autoInsertDiv.appendChild(autoInsertSpan);

        // Append auto-insert div to show-all-download-buttons container
        insertAllContainer.appendChild(autoInsertDiv);

        // Check if the checkbox is checked
        if (autoInsertCheckbox.checked) {
            clickAllGrabButtons();
        }
}


// Check if the current URL includes freesound.org/search
if (window.location.href.includes("freesound.org/search")) {
    console.log('URL matched: freesound.org/search');

    // Find all instances of '.bw-search__result' within the 'main' element
    const searchResults = document.querySelectorAll('main .bw-search__result');

    // Loop through each search result
    searchResults.forEach(result => {
        // Find the first <a> element within the search result
        const firstLink = result.querySelector('a');

        // Check if a <a> element is found
        if (firstLink) {
            // Print the href attribute of the first <a> element to the console
            console.log('First link href:', firstLink.href);

            // If grabMode is true, insert a new div at the end of the search result
            createGrabButtons(result, true, '');
        } else {
            console.log('No link found in search result');
        }
    });

    // Find the very first search result element
    const firstSearchResult = document.querySelector('main .bw-search__result:first-child');

    // Check if the first search result element is found
    if (firstSearchResult) {
        createInsertAllButton(firstSearchResult);
    } else {
        console.log('No search results found');
    }
} else {
    console.log('URL did not match: freesound.org/search');

    // Check if the page includes one or more instances of .bw-player
    const bwPlayers = document.querySelectorAll('.bw-player');
    if (bwPlayers.length >= 1) {
        console.log('One or more instances of .bw-player were found:', bwPlayers.length);

      // Initialize an array to store common ancestors
        var commonAncestors = [];

        // Loop through each .bw-player instance
        bwPlayers.forEach(player => {
          // Initialize an array to store ancestors of the current .bw-player instance
            var ancestors = [];

            // Find the parent element of the .bw-player instance
            const parentElement = player.parentNode;
            // Create and append grab buttons
            createGrabButtons(parentElement, true, 'in-row');

// Traverse up the DOM tree and store ancestors until reaching the document body
            var ancestor = player.parentNode;
            while (ancestor !== document.body) {
                ancestors.push(ancestor);
                ancestor = ancestor.parentNode;
            }

            // Add ancestors of the current .bw-player instance to the common ancestors array
            commonAncestors = commonAncestors.length === 0 ? ancestors : commonAncestors.filter(ancestor => ancestors.includes(ancestor));
        });

// Find the lowest-level common ancestor
      console.log("commonAncestors: ");
      commonAncestors.forEach(ancestor => {
            console.log(ancestor);
        });

function findLowestLevelCommonAncestor(commonAncestors) {
    var lowestCommonAncestor = commonAncestors[0]; // Initialize with the first element

    // Iterate through the common ancestors array
    for (let i = 1; i < commonAncestors.length; i++) {
        const currentAncestor = commonAncestors[i];
        // Check if the current ancestor is deeper in the hierarchy than the current lowest common ancestor
        if (lowestCommonAncestor.contains(currentAncestor)) {
            lowestCommonAncestor = currentAncestor;
        }
    }

    return lowestCommonAncestor;
}

        const lowestCommonAncestor = findLowestLevelCommonAncestor(commonAncestors);
        console.log('Lowest level common ancestor:', lowestCommonAncestor);

        // Pass the lowest-level common ancestor to the createInsertAllButton function
        createInsertAllButton(lowestCommonAncestor);
    } else {
        console.log('No instances of .bw-player were found');
    }
}

// Function to handle auto-insert checkbox change
function handleAutoInsertChange() {
    // Get the auto-insert checkbox
    const autoInsertCheckbox = document.querySelector('.auto-insert-div input[type="checkbox"]');

    // Update the local storage value
    localStorage.setItem('autoInsertCheckbox', autoInsertCheckbox.checked);

    // Check if the checkbox is checked
    if (autoInsertCheckbox.checked) {
        clickAllGrabButtons();
    }
}

// Function to click all grab buttons
function clickAllGrabButtons() {
    const grabButtons = document.querySelectorAll('.grab-button');
    grabButtons.forEach(button => {
        grabHtmlAndReplaceButton(button);
    });
}

// Add stylesheet to the page head
const style = document.createElement('style');
style.id = 'new-script-css';
style.innerHTML = `
    .grabber {
        width: 100%;
        margin: 0 0 12px;
        text-align: center;
    }

    .grabber .grab-button {
        background: #CCC;
        padding: 4px 8px;
        border: 1px solid black;
        border-radius: 1em;
    }

    .grabber.in-row {
        margin-top: 12px;
    }

    .grabber.in-row .grab-button {
        font-size: .75em;
    }

    .grabber.in-row .btn-primary {
      padding: 9px 21px;
    }

    .show-all-download-buttons {
        margin-bottom: 32px;
        text-align: center;
        --sadb-border-style: 1px solid hsla(0, 0%, 0%, .5);
        border-bottom: var(--sadb-border-style);
        border-top: var(--sadb-border-style);
    }

    .insert-all-download-buttons {
        margin: 12px 0 6px;
    }

    .auto-insert-div {
        margin-bottom: 12px;
        justify-content: center;
        align-items: center;
        display: flex;
    }

    .auto-insert-div * {
        margin: 0 .35em;
    }
`;
document.head.appendChild(style);