Adds download links on freesound.org. Works with a button press, or automatically.
当前为
// ==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);