VocaloidLyrics.fandom.com lyrics copier
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
(() => { | |
let romajiHeader = Array.from(document.querySelectorAll(":is(td,th)")).filter(e => e.textContent.trim() == "Romaji")[0]; | |
let table = romajiHeader.parentNode.parentNode; | |
let isThead = table.tagName == "THEAD"; | |
if(!isThead) { | |
table = table.parentNode.getElementsByTagName("TBODY")[0]; | |
} | |
let rows = Array.from(table.children); | |
let columnCount = rows[0].children.length; | |
let output = Array.from(Array(columnCount), ()=>[]); | |
for(let rowIndex = 0; rowIndex < rows.length; rowIndex++) { | |
let row = rows[rowIndex]; | |
for(let columnIndex = 0; columnIndex < columnCount; columnIndex++) { | |
let column = row.children[columnIndex] ?? row.children[0]; | |
let columnText = (column?.innerText?.trim() ?? "") + "\n"; | |
output[columnIndex].push(columnText); | |
} | |
} | |
let dialog = document.createElement("DIALOG"); | |
dialog.style.resize = "vertical"; | |
dialog.style.display = "flex"; | |
dialog.style.flexDirection = "column"; | |
dialog.style.height = "60vh"; | |
dialog.style.minHeight = "200px"; | |
document.body.append(dialog); | |
let h1 = document.createElement("H1"); | |
h1.textContent = "Lyrics copier"; | |
dialog.append(h1); | |
let h2 = document.createElement("H2"); | |
let authorLink = document.createElement("A"); | |
authorLink.href = "https://github.com/TheChilliPL"; | |
authorLink.textContent = "Chilli!" | |
h2.append("by ", authorLink); | |
dialog.append(h2); | |
let container = document.createElement("DIV"); | |
container.style.display = "flex"; | |
container.style.flexGrow = "1"; | |
let textareas = []; | |
let syncScroll = true; | |
let ignoreScrollEvents = 0; | |
for(let column of output) { | |
let textarea = document.createElement("TEXTAREA"); | |
textarea.textContent = column.join(""); | |
textarea.style.resize = "horizontal"; | |
textarea.style.minWidth = "100px"; | |
textarea.style.whiteSpace = "pre"; | |
textarea.style.lineHeight = "1.2"; | |
textarea.readOnly = true; | |
textarea.addEventListener("resize", console.debug); | |
textarea.addEventListener("scroll", () => { | |
if (!syncScroll) return; | |
if (ignoreScrollEvents) { | |
ignoreScrollEvents--; | |
return; | |
} | |
let scroll = textarea.scrollTop; | |
for (let area of textareas) { | |
if (area != textarea) { | |
ignoreScrollEvents++; | |
area.scrollTop = scroll; | |
} | |
} | |
}); | |
container.append(textarea); | |
textareas.push(textarea); | |
} | |
dialog.append(container); | |
let hint = document.createElement("P"); | |
hint.style.fontSize = "80%"; | |
hint.style.opacity = "0.8"; | |
let hintLink = document.createElement("A"); | |
hintLink.href = "https://gist.github.com/TheChilliPL/d4b8225a3b6a1087b80735c167130e28"; | |
hintLink.textContent = "See the source on GitHub."; | |
hint.append( | |
"You can select and copy text from each column now.", | |
document.createElement("BR"), | |
hintLink | |
); | |
dialog.append(hint); | |
let syncCheckboxLabel = document.createElement("LABEL"); | |
let syncCheckbox = document.createElement("INPUT"); | |
syncCheckbox.type = "checkbox"; | |
syncCheckbox.checked = true; | |
syncCheckbox.addEventListener("change", () => { | |
let checked = syncCheckbox.checked; | |
if (checked) { | |
let averageScroll = textareas.map(area => area.scrollTop).reduce((a, b) => a + b) / textareas.length; | |
textareas.forEach(area => area.scrollTop = averageScroll); | |
} | |
syncScroll = checked; | |
}); | |
syncCheckboxLabel.append(syncCheckbox, "Synchronize scroll position"); | |
dialog.append(syncCheckboxLabel); | |
let form = document.createElement("FORM"); | |
form.method = "dialog"; | |
dialog.append(form); | |
let button = document.createElement("BUTTON"); | |
button.textContent = "Close modal [Esc]"; | |
button.style.width = "100%"; | |
form.append(button); | |
dialog.addEventListener("close", () => { | |
dialog.remove(); | |
}); | |
dialog.showModal(); | |
return output; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment