Show lyrics on Lyricstraining
// ==UserScript==
// @name Show lyrics LT
// @namespace http://tampermonkey.net/
// @version 2025-01-04
// @description Show lyrics on Lyricstraining
// @author Valerio Valletta
// @match https://lyricstraining.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=lyricstraining.com
// @grant none
// ==/UserScript==
var autoScroll = true;
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(";");
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == " ") c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function dragElement(elmnt) {
var pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
const oldBoxPos = getCookie("lyrics-box-pos");
if (oldBoxPos) {
const { top, left } = JSON.parse(oldBoxPos);
elmnt.style.top = top;
elmnt.style.left = left;
}
if (document.getElementById(elmnt.id + "-header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "-header").onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
const lyricsBox = document.querySelector("#lyrics-box");
const lastBoxPos = {
top: lyricsBox.style.top,
left: lyricsBox.style.left,
};
setCookie("lyrics-box-pos", JSON.stringify(lastBoxPos));
document.onmouseup = null;
document.onmousemove = null;
}
}
function scrollParentToChild(parent, child) {
// Where is the parent on page
var parentRect = parent.getBoundingClientRect();
// What can you see?
var parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth,
};
// Where is the child
var childRect = child.getBoundingClientRect();
// Calculate the child's center relative to the parent's center
var childCenterY = childRect.top + childRect.height / 2;
var parentCenterY = parentRect.top + parentViewableArea.height / 2;
// Calculate the distance to scroll
var scrollY = childCenterY - parentCenterY;
// Adjust the parent's scroll position
parent.scrollTop += scrollY;
}
const createLyricsBox = () => {
const lyricsBox = document.createElement("div");
lyricsBox.id = "lyrics-box";
lyricsBox.style.display = "none";
lyricsBox.style.zIndex = 50;
lyricsBox.style.position = "absolute";
lyricsBox.style.right = 0;
lyricsBox.style.bottom = 10;
lyricsBox.style.width = "100%";
lyricsBox.style.height = "100%";
lyricsBox.style.maxHeight = "300px";
lyricsBox.style.maxWidth = "700px";
lyricsBox.style.overflowY = "scroll";
lyricsBox.style.backgroundColor = "#FFF";
lyricsBox.style.boxShadow = "rgba(0, 0, 0, 0.24) 0px 3px 8px";
lyricsBox.appendChild(createLyricsBoxHeader());
return lyricsBox;
};
function createCheckbox() {
// Create the input element
const input = document.createElement("input");
// Set attributes
input.type = "checkbox";
input.id = "switch-autoscroll";
input.style.transform = "scale(1.5)";
input.checked = true;
input.onclick = toggleAutoScroll;
return input;
}
const toggleAutoScroll = () => {
autoScroll = !autoScroll;
document.querySelector("#switch-autoscroll").checked = autoScroll;
};
const createSwitchAutoScroll = () => {
const div = document.createElement("div");
div.style.display = "flex";
div.style.justifyContent = "center";
div.style.alignItems = "center";
div.style.padding = "0.5em";
const text = document.createElement("span");
text.innerText = "autoscroll";
text.style.fontSize = "1.3em";
text.style.color = "white";
text.style.paddingRight = "0.3em";
const checkbox = createCheckbox();
div.append(text);
div.appendChild(checkbox);
return div;
};
const createLyricsBoxHeader = () => {
const header = document.createElement("div");
header.id = "lyrics-box-header";
header.style.top = 0;
header.style.position = "sticky";
header.style.width = "100%";
header.style.height = "100%";
header.style.maxHeight = "50px";
header.style.backgroundColor = "royalblue";
header.style.cursor = "move";
header.style.display = "flex";
header.style.alignItems = "center";
header.style.justifyContent = "space-between";
const title = document.createElement("span");
title.innerText = "DRAG ME";
title.style.fontSize = "1.6em";
title.style.color = "white";
title.style.fontWeight = "bold";
title.style.letterSpacing = "0.3em";
title.style.padding = "0.5em";
const switchAutoScroll = createSwitchAutoScroll();
header.appendChild(title);
header.appendChild(switchAutoScroll);
return header;
};
const createShowLyricsBtn = () => {
const btn = document.createElement("button");
btn.id = "show-lyrics-btn";
btn.innerText = "SHOW LYRICS";
btn.style.fontSize = "1.5em";
btn.style.fontWeight = "bold";
btn.style.zIndex = 100;
btn.style.position = "fixed";
btn.style.right = 0;
btn.style.bottom = 10;
btn.style.border = "2px solid royalblue";
btn.style.borderRight = "0px";
btn.style.color = "royalblue";
btn.style.background = "white";
btn.style.cursor = "pointer";
btn.style.transition = "0.5s all";
return btn;
};
(function () {
"use strict";
const addOptions = document.querySelector("#add-options");
const lyricsBox = createLyricsBox();
lt.game.page.lyrics.lines
.map((el) => el.text)
.forEach((el, i) => {
const p = document.createElement("p");
p.className = "lyric-line";
p.id = `line-${i}`;
p.style.fontSize = "1.5em";
p.style.color = "white";
p.style.paddingLeft = "1em";
p.innerText = el;
lyricsBox.appendChild(p);
});
const btn = createShowLyricsBtn();
btn.addEventListener("mouseenter", () => {
let btn = document.querySelector("#show-lyrics-btn");
btn.style.fontSize = "1.6em";
});
btn.addEventListener("mouseleave", () => {
let btn = document.querySelector("#show-lyrics-btn");
btn.style.fontSize = "1.5em";
});
btn.addEventListener("click", () => {
let currStatus = document.querySelector("#lyrics-box").style.display;
if (currStatus === "none") {
document.querySelector("#lyrics-box").style.display = "block";
return;
}
document.querySelector("#lyrics-box").style.display = "none";
return;
});
addOptions.appendChild(btn);
addOptions.appendChild(lyricsBox);
dragElement(lyricsBox);
var trackLineVisible = new Set();
setInterval(() => {
if (trackLineVisible) [hideVisibleLines()];
const lineEls = document.querySelectorAll(".lyric-line");
const currEl = lineEls[lt.game.page.playView.playLine];
if (!lineEls || !currEl) return;
currEl.style.color = "green";
currEl.style.display = "block";
if (autoScroll) {
scrollParentToChild(lyricsBox, currEl);
}
trackLineVisible.add(currEl);
}, 500);
const hideVisibleLines = () => {
trackLineVisible.forEach((el) => {
el.style.color = "black";
});
trackLineVisible.clear();
};
})();