Last active
December 29, 2023 13:16
-
-
Save mzywiol/574b0d66c318530b1fb4 to your computer and use it in GitHub Desktop.
GreaseMonkey script to copy song lyrics from popular lyrics websites with just one click! Click on a button next to the song text and it'll get copied in its entirety to your clipboard. Works with: lyrics.wikia, A-Z Lyrics, Direct Lyrics, Songtexte, Genius.com, Musixmatch, Lyricsmode, Lyricsfreak, Tekstowo.pl, Sing365. Additionally, it removes f…
This file contains 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 Copy lyrics | |
// @namespace xz | |
// @description Copy lyrics from popular lyrics websites | |
// @include http://lyrics.wikia.com/* | |
// @include http://www.azlyrics.com/* | |
// @include http://www.directlyrics.com/* | |
// @include http://www.songtexte.com/* | |
// @include *genius.com* | |
// @include *www.musixmatch.com/lyrics/* | |
// @include *www.lyricsmode.com/lyrics/* | |
// @include *www.lyricsfreak.com/* | |
// @include *www.sing365.com/* | |
// @include *www.tekstowo.pl/piosenka* | |
// @include *google*/search*lyrics* | |
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js | |
// @version 1 | |
// @grant none | |
// ==/UserScript== | |
var host = location.hostname; | |
var lyricboxSelector = undefined; | |
var triggerSelector = undefined; | |
var buttonLeft = "30px"; | |
var buttonTop = "30px"; | |
var cleanup = stripHTML; | |
function replaceAll(string, search, replacement) { | |
return string.replace(new RegExp(search, 'g'), replacement); | |
}; | |
function stripScripts(html) { | |
return replaceAll(html, "<script>.*<\/script>", ""); | |
} | |
function stripComments(html) { | |
return replaceAll(html, "<!.*>", ""); | |
} | |
function stripTags(html) { | |
var tmp = document.createElement("DIV"); | |
tmp.innerHTML = html; | |
return tmp.textContent || tmp.innerText || ""; | |
} | |
function joinSoftEnters(html) { | |
return replaceAll(html, "\n", ""); | |
} | |
function newlinesFromBr(html) { | |
return replaceAll(html, "<br\/?>", "\n"); | |
} | |
function stripHTML(text) { | |
return stripTags(stripComments(stripScripts(fixEnters(text)))); | |
} | |
function fixEnters(text) { | |
return newlinesFromBr(joinSoftEnters(text)); | |
} | |
function copyLyricsToTextarea(sourceElem, targetId, cleanup) { | |
var target = document.getElementById(targetId); | |
if (!target) { | |
var target = document.createElement("textarea"); | |
target.style.position = "absolute"; | |
target.style.left = "-9999px"; | |
target.style.top = "0"; | |
target.id = targetId; | |
document.body.appendChild(target); | |
} | |
target.textContent = cleanup(sourceElem.innerHTML); | |
return target; | |
} | |
function copyToClipboard(elem, cleanup) { | |
// create hidden text element, if it doesn't already exist | |
var targetId = "_hiddenCopyText_"; | |
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA"; | |
var origSelectionStart, origSelectionEnd; | |
if (isInput) { | |
// can just use the original source element for the selection and copy | |
var target = elem; | |
origSelectionStart = elem.selectionStart; | |
origSelectionEnd = elem.selectionEnd; | |
} else { | |
// must use a temporary form element for the selection and copy | |
var target = copyLyricsToTextarea(elem, targetId, cleanup); | |
} | |
// select the content | |
var currentFocus = document.activeElement; | |
target.focus(); | |
target.setSelectionRange(0, target.value.length); | |
// copy the selection | |
var succeed; | |
try { | |
succeed = document.execCommand("copy"); | |
} catch(e) { | |
succeed = false; | |
} | |
// restore original focus | |
if (currentFocus && typeof currentFocus.focus === "function") { | |
currentFocus.focus(); | |
} | |
if (isInput) { | |
// restore prior selection | |
elem.setSelectionRange(origSelectionStart, origSelectionEnd); | |
} else { | |
// clear temporary content | |
target.textContent = ""; | |
} | |
return succeed; | |
} | |
$(function() { (function ($) { | |
if (host.contains("google")) { | |
jQuery("a:contains('MetroLyrics')").parentsUntil("div.g").remove() | |
return 0; | |
} | |
switch (host) { | |
case "lyrics.wikia.com": | |
lyricboxSelector = "div.lyricbox"; | |
break; | |
case "www.azlyrics.com": | |
lyricboxSelector = "div.ringtone ~ div:first"; | |
break; | |
case "www.directlyrics.com": | |
triggerSelector = "div.lyricsselect"; | |
lyricboxSelector = "div.lyricsselect p"; | |
buttonTop = "100px"; | |
buttonLeft = "640px"; | |
break; | |
case "www.songtexte.com": | |
lyricboxSelector = "div#lyrics"; | |
buttonTop = "150px"; | |
buttonLeft = "50px"; | |
break; | |
case "genius.com": | |
lyricboxSelector = "div.song_body-lyrics lyrics"; | |
buttonTop = "10px"; | |
buttonLeft = "490px"; | |
break; | |
case "www.musixmatch.com": | |
triggerSelector = "div.container"; | |
lyricboxSelector = "p.mxm-lyrics__content"; | |
cleanup = stripTags; | |
break; | |
case "www.lyricsmode.com": | |
triggerSelector = "div.inner-song-page-content"; | |
lyricboxSelector = "p#lyrics_text"; | |
buttonLeft = "500px"; | |
break; | |
case "www.lyricsfreak.com": | |
lyricboxSelector = "div.lyrictxt"; | |
buttonTop = "10px"; | |
buttonLeft = "430px"; | |
break; | |
case "www.sing365.com": | |
lyricboxSelector = "div#main section"; | |
triggerSelector = "h1"; | |
buttonTop = "0px"; | |
buttonLeft = "-120px"; | |
cleanup = function(text) { | |
var text = text.substring(0, text.indexOf("<a")).substring(text.lastIndexOf("</script>") + 9); | |
return stripHTML(text); | |
}; | |
break; | |
case "www.tekstowo.pl": | |
lyricboxSelector = "div.song-text"; | |
buttonTop = "550px"; | |
buttonLeft = "300px"; | |
cleanup = function(text) { | |
var text = text.substring(text.indexOf("</h2>") + 5, text.indexOf("<a")); | |
return stripHTML(text); | |
}; | |
break; | |
} | |
// copy lyrics upon clicking on them on the page | |
// jQuery(triggerSelector || lyricboxSelector).click(function() { | |
// if (copyToClipboard(jQuery(lyricboxSelector)[0], cleanup)) { | |
// window.alert("Lyrics successfully copied!"); | |
// } | |
// }); | |
// create button on page to copy lyrics | |
var copyLyricsButton = document.createElement("input"); | |
copyLyricsButton.type = "button"; | |
copyLyricsButton.value = "Copy lyrics"; | |
copyLyricsButton.style.cssText = [ | |
"position: absolute", | |
"left: " + buttonLeft, | |
"top: " + buttonTop, | |
"width: 100px", | |
"height: 100px", | |
"border-radius: 50%", | |
"background-color: #97f", | |
"border: 4px outset #b9f", | |
"color: black", | |
"font-weight: bold", | |
"font-size: 20px", | |
"white-space: normal", | |
"z-index: 1000" | |
].join(";"); | |
copyLyricsButton.id = "__xz__copyLyricsButton__"; | |
jQuery(triggerSelector || lyricboxSelector).append(copyLyricsButton); | |
jQuery("input#__xz__copyLyricsButton__").click(function() { | |
if (copyToClipboard(jQuery(lyricboxSelector)[0], cleanup)) { | |
var button = jQuery(this); | |
button.css("background-color", "green"); | |
button.css("border-color", "#2f2"); | |
button.attr("value", "Copied!"); | |
} else { | |
var button = jQuery(this); | |
button.css("background-color", "red"); | |
button.css("border-color", "#f22"); | |
button.attr("value", "Failed to copy."); | |
} | |
}); | |
})(jQuery)}); |
Update: added support for Tekstowo.pl and switched to the button trigger as default, instead of clicking on song text.
For some reason Musixmatch doesn't want to cooperate with the button. Will investigate.
Will this be updated some more? It doesn't work with Musixmatch right now :/
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added support for Sing365 and commented out alternate trigger for copying: a button that shows up on lyrics page. It's commented out since it's not placed properly on all supported pages. May need to add custop placement coordinates for some pages.