您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
helpful utilities when working with song lyrics and OpenSong
当前为
// ==UserScript== // @name lyricUtils v2 // @namespace Violentmonkey Scripts // @include https://www.azlyrics.com/lyrics/* // @include https://www.letras.com/* // @include https://4334.sk/* // @include https://www.songlyrics.com/* // @include https://www.lyrics.com/track/* // @include https://bethelmusic.com/chords-and-lyrics/* // @grant none // @version 2.3 // @author KraXen72 // @locale en-US // @license GPLv3 // @description helpful utilities when working with song lyrics and OpenSong // ==/UserScript== // the current site let site = { n: "", // name querySelector: "", // where to get text from holderqs: "", // where to inject our versed div textKey: "" // what to use to get text (for exampe innerText or textContent) } function determineSite() { //console.log(window.location.hostname) switch (window.location.hostname) { case "4334.sk": site.n = "4334"; site.holderqs = ".entry-content" break; case "www.letras.com": site.n = "letras"; site.querySelector = ".cnt-letra.p402_premium" site.holderqs = "overwrite" site.textKey = "innerText" break; case "www.azlyrics.com": site.n = "azlyrics"; site.querySelector = ".col-xs-12.col-lg-8.text-center div:not([class]):not([id])"; site.holderqs = ".col-xs-12.col-lg-8.text-center" site.textKey = "textContent" break; case "www.songlyrics.com": site.n = "songlyrics" site.querySelector = "#songLyricsDiv" site.holderqs = "overwrite" site.textKey = "textContent" break; case "www.lyrics.com": site.n = "lyricscom" site.querySelector = "#lyric-body-text" site.holderqs = "overwrite" site.textKey = "innerText" break; case "bethelmusic.com": site.n = "bethel" site.holderqs = "#tabLyrics" site.textKey = "innerText" default: console.error(`unknown site ${window.location.hostname}`); } } function injectCSS(css) { const styleTag = document.createElement("style") styleTag.innerHTML = css document.head.appendChild(styleTag) } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function makeBtn(text, onclick) { const btn = document.createElement("button") btn.classList.add("lyricUtils-button") btn.style.padding = ".5rem" btn.style.border = "2px solid darkblue" btn.style.borderRadius = "5px" btn.style.margin = "0 .25rem" btn.onclick = onclick btn.textContent = text return btn } function copyMe(textToCopy) { const TempText = document.createElement("textarea"); TempText.value = textToCopy; //TempText.style.display = "none" document.body.appendChild(TempText); TempText.select(); document.execCommand("copy"); document.body.removeChild(TempText); console.log("copied stuff", textToCopy) } function groupToVerses(text) { const lines = text.split("\n") const newLines = [...lines].filter(l => l !== "Hide Chords") let verses = [""] // starts with empty verse console.log("nl", newLines) for (let i = 0; i < newLines.length; i++) { const l = newLines[i] if (l === "") { verses.push("") // start a new verse } else { verses[verses.length - 1] += l + "<br>" // continue an existing verse } } verses = verses.filter(v => v !== "") // filter out empty verses return verses } function getTextContent() { let stuff = "" const newHolder = document.getElementById("lyricUtils-holder") Array.from(newHolder.children).forEach(child => { if (!(child.classList.contains("lyricUtils-button"))) stuff += child.innerText if (child.classList.contains("lyricUtils-vhead") || child.classList.contains("lyricUtils-verse")) stuff += "\n" }) console.log(stuff) return stuff } function constructVerseElement(verses) { const holder = document.createElement("div") holder.id = "lyricUtils-holder" verses.forEach((v, index, arr) => { const vDiv = document.createElement("div") vDiv.id = `V${index + 1}-lyricUtils` vDiv.classList.add("lyricUtils-verse") vDiv.innerHTML = v //vDiv.style.margin = "1rem 0" holder.appendChild(vDiv) if (index !== arr.length -1) holder.appendChild(document.createElement("br")) }) return holder } function addHeaders() { if (document.querySelector(".lyricUtils-vhead") === null) { const allVerses = [...document.getElementsByClassName("lyricUtils-verse")] const newHolder = document.getElementById("lyricUtils-holder") allVerses.forEach(verse => { const vHead = document.createElement("div") vHead.classList.add("lyricUtils-vhead") vHead.textContent = `[${verse.id.split("-")[0]}]` // VXX-lyricUtils => [VXX] newHolder.insertBefore(vHead, verse) }) } else { console.log("headers already added") } } function removeHeaders() { [...document.getElementsByClassName("lyricUtils-vhead")].forEach(head => head.remove()) } const elem = (qs) => { if (typeof qs === "string") return document.querySelector(qs) return qs } const text = (qs, key) => { if (typeof qs === "string") return document.querySelector(qs)[key] return qs[key] } const extractors = { _standard: (qs, key) => { const rawText = text(qs, key) const verses = groupToVerses(rawText) const ourElement = constructVerseElement(verses) if (site.holderqs === "overwrite") { elem(site.querySelector).innerHTML = ourElement.innerHTML elem(site.querySelector).id = "lyricUtils-holder" //has to go second, because qs can be an id selector } else { const holder = document.querySelector(site.holderqs) holder.insertBefore(ourElement, elem(site.querySelector).nextElementSibling) } const newHolder = document.getElementById("lyricUtils-holder") newHolder.prepend(makeBtn("📋", () => { copyMe(getTextContent()) })) newHolder.prepend(makeBtn("⛔", removeHeaders)) newHolder.prepend(makeBtn("➕", addHeaders)) console.log(site.n) console.log(verses) }, azlyrics: () => { injectCSS(`${site.querySelector} { display: none !important; }`) extractors._standard(site.querySelector, site.textKey) }, letras: () => { injectCSS(`#player { display: none !important; } ::selection { background: #dcdc00 !important; }`); extractors._standard(site.querySelector, site.textKey) }, 4334: () => { injectCSS(` div[style*="visibility: visible; position: absolute;"] { display: none !important; } .entry-content { display: flex; flex-direction: row-reverse; justify-content: space-between } `) // fix up stuff for copying: 4334 has chord divs in the text const clonedText = document.querySelector(".chordwp-container").cloneNode(true) const wrappers = [...clonedText.querySelectorAll(".chwp-lyrics-row-wrapper")] lines = [] wrappers.forEach(w => { const lyr = [...w.querySelectorAll(".chwp-lyrics")] let txt = [] lyr.forEach(l => txt.push(l.textContent)) lines.push(`<div class="line">${txt.join("")}</div>`) if (w.nextElementSibling && w.nextElementSibling.tagName === "BR") lines.push(`<div class="line"><br></div>`) }) clonedText.innerHTML = lines.join("\n") site.querySelector = clonedText site.textKey = "innerText" extractors._standard(site.querySelector, site.textKey) }, songlyrics: () => { injectCSS(` .iComment-popup { display: none !important; pointer-events: none !important; } #lyricUtils-holder { font-size: 16px; line-height: 1.6; } `) extractors._standard(site.querySelector, site.textKey) }, lyricscom: () => { extractors._standard(site.querySelector, site.textKey) }, bethel: () => { const lyricsDiv = document.createElement("div") lyricsDiv.innerHTML = document.querySelector("#tabLyrics .content").innerHTML const bTags = [...lyricsDiv.querySelectorAll("p > b")] bTags.forEach(b => b.remove()) injectCSS(` #tabLyrics { display: grid; grid-template: auto / max-content max-content auto; column-gap: 1rem; } #lyricUtils-holder { font-size: 16px; line-height: 2; grid-colum: 2 / 3 } #tabLyrics .content { grid-colum: 1 / 2 } .nav.nav-tabs { display: none !important; poiner-events: none; } `) site.querySelector = lyricsDiv extractors._standard(lyricsDiv, site.textKey) } } determineSite() extractors[site.n]()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址