Last active
March 12, 2025 09:03
-
-
Save pckv/ea2e8e72f6a8f327fb204296266c3dcf to your computer and use it in GitHub Desktop.
Lyrical-nonsense Copy Userscript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Lyrical-nonsense Copy | |
// @namespace http://tampermonkey.net/ | |
// @version 0.3 | |
// @description Enables copying in lyric text and adds a copy lyrics button to each tab | |
// @author pckv | |
// @match https://www.lyrical-nonsense.com/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=lyrical-nonsense.com | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
function addUserSelectToLyrics() { | |
// Add the CSS definition if it doesn't exist | |
if ( | |
!document.head.querySelector("style").innerHTML.includes(".allow-select") | |
) { | |
// Add a new css class definition to the page | |
const style = document.createElement("style"); | |
style.innerHTML = ` | |
.allow-select { | |
user-select: text !important; | |
-webkit-user-select: text !important; | |
-moz-user-select: text !important; | |
-ms-user-select: text !important; | |
-khtml-user-select: text !important; | |
-webkit-touch-callout: unset !important; | |
} | |
`; | |
document.head.appendChild(style); | |
} | |
// Make all text inside lyrics containers selectable | |
const elementsWithLyrics = document.querySelectorAll(".olyrictext"); | |
elementsWithLyrics.forEach((element) => { | |
element.classList.add("allow-select"); | |
}); | |
} | |
function copyLyricsToClipboard(parentId) { | |
// Find lyrics inside the parent element | |
const lyricsParentElement = document.querySelector( | |
`#${parentId} .olyrictext` | |
); | |
// Get the lyrics as a string | |
let lyrics = Array.from(lyricsParentElement.children) | |
.map((element) => element.innerText) | |
.join("\n"); | |
// Remove any duplicate empty lines | |
lyrics = lyrics.replace(/\n\n\n/g, "\n\n"); | |
// Remove any leading or trailing whitespace from each line | |
lyrics = lyrics | |
.split("\n") | |
.map((line) => line.trim()) | |
.join("\n"); | |
// Copy the lyrics to the clipboard | |
navigator.clipboard.writeText(lyrics); | |
} | |
function addCopyLyricsToClipboardButton(parentId) { | |
// Skip if the button already exists | |
if (document.querySelector(`#${parentId} .copy-lyrics-button`)) { | |
return; | |
} | |
// Find the theme selector button | |
const themeSelector = document.querySelector( | |
`#${parentId} .theme-selector2` | |
); | |
if (!themeSelector) { | |
return; | |
} | |
// Create the copy lyrics button | |
const copyButton = document.createElement("button"); | |
copyButton.classList.add("lyric-control-container", "copy-lyrics-button"); | |
copyButton.innerHTML = "Copy Lyrics"; | |
copyButton.style.backgroundColor = "white"; | |
copyButton.addEventListener("click", () => { | |
copyLyricsToClipboard(parentId); | |
// Change the color of the button to indicate that the lyrics have been copied | |
copyButton.style.backgroundColor = "#4CAF50"; | |
// Transition the color back to the original color | |
setTimeout(() => { | |
copyButton.style.backgroundColor = "white"; | |
}, 2500); | |
}); | |
// Add the button to the DOM after the theme selector button | |
themeSelector.after(copyButton); | |
} | |
function addCopyLyricsToClipboardButtonToAllTabs() { | |
// Find all lyrics tabs | |
const tabDivs = document.querySelector(".contentsblock"); | |
const tabs = Array.from(tabDivs.children).map((element) => element.id); | |
// Add the copy lyrics button to each tab | |
tabs.forEach((tab) => { | |
// If there are sub-tabs, add the button to each sub-tab | |
// This is used for the translations tab | |
const subTabDivs = document.querySelector(`#${tab} .subcontentsblock`); | |
if (subTabDivs) { | |
const subTabs = Array.from(subTabDivs.children).map( | |
(element) => element.id | |
); | |
subTabs.forEach((subTab) => { | |
addCopyLyricsToClipboardButton(subTab); | |
}); | |
return; | |
} | |
// Otherwise, add the button to the tab | |
addCopyLyricsToClipboardButton(tab); | |
}); | |
} | |
function removeHighlightAndShareWrapper() { | |
// Remove the highlight and share wrapper if it exists | |
const highlightAndShareWrapper = document.querySelector( | |
".highlight-and-share-wrapper" | |
); | |
if (highlightAndShareWrapper) { | |
highlightAndShareWrapper.remove(); | |
} | |
} | |
// Create a MutationObserver to watch for changes in the DOM to | |
// always apply the script to new elements | |
const observer = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
if (mutation.addedNodes.length > 0) { | |
addUserSelectToLyrics(); | |
addCopyLyricsToClipboardButtonToAllTabs(); | |
removeHighlightAndShareWrapper(); | |
} | |
}); | |
}); | |
// Start observing the entire document for changes | |
observer.observe(document.body, { childList: true, subtree: true }); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment