Fetch Download Links on FreeSound.org

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

目前為 2024-04-23 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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);