// @ts-check
// NAME: Loopy loop
// AUTHOR: khanhas
// VERSION: 0.1
// DESCRIPTION: Simple tool to help you practice hitting that note right. Right click at process bar to open up menu.
///
(function LoopyLoop() {
const bar = document.querySelector(".playback-bar .progress-bar");
if (!bar) {
setTimeout(LoopyLoop, 100);
return;
}
const style = document.createElement("style");
style.innerHTML = `
#loopy-loop-start, #loopy-loop-end {
position: absolute;
font-weight: bolder;
font-size: 15px;
top: -7px;
}
`;
const startMark = document.createElement("div");
startMark.id = "loopy-loop-start";
startMark.innerText = "[";
const endMark = document.createElement("div");
endMark.id = "loopy-loop-end";
endMark.innerText = "]";
startMark.style.position = endMark.style.position = "absolute";
startMark.hidden = endMark.hidden = true;
bar.append(style);
bar.append(startMark);
bar.append(endMark);
let start = null,
end = null;
let mouseOnBarPercent = 0.0;
function drawOnBar() {
if (start === null && end === null) {
startMark.hidden = endMark.hidden = true;
return;
}
startMark.hidden = endMark.hidden = false;
startMark.style.left = start * 100 + "%";
endMark.style.left = end * 100 + "%";
}
function reset() {
start = null;
end = null;
drawOnBar();
}
let debouncing = 0;
Spicetify.Player.addEventListener("onprogress", (event) => {
if (start != null && end != null) {
if (debouncing) {
if (event.timeStamp - debouncing > 1000) {
debouncing = 0;
}
return;
}
const percent = Spicetify.Player.getProgressPercent();
if (percent > end || percent < start) {
debouncing = event.timeStamp;
Spicetify.Player.seek(start);
return;
}
}
});
Spicetify.Player.addEventListener("songchange", reset);
const startBtn = new _HTMLContextMenuItem({ name: "Set start" });
startBtn.onclick = () => {
start = mouseOnBarPercent;
if (end === null || start > end) {
end = 0.99;
}
drawOnBar();
};
const endBtn = new _HTMLContextMenuItem({ name: "Set end" });
endBtn.onclick = () => {
end = mouseOnBarPercent;
if (start === null || end < start) {
start = 0;
}
drawOnBar();
};
const resetBtn = new _HTMLContextMenuItem({ name: "Reset" });
resetBtn.onclick = reset;
const contextMenu = document.createElement("div");
contextMenu.id = "loopy-context-menu";
contextMenu.innerHTML = `
`;
contextMenu.style.position = "absolute";
contextMenu.firstElementChild.append(startBtn, endBtn, resetBtn);
document.body.append(contextMenu);
const { height: contextMenuHeight } = contextMenu.getBoundingClientRect();
contextMenu.hidden = true;
window.addEventListener("click", () => (contextMenu.hidden = true));
bar.oncontextmenu = (event) => {
const { x, width } = bar.firstElementChild.getBoundingClientRect();
mouseOnBarPercent = (event.clientX - x) / width;
contextMenu.style.transform = `translate(${event.clientX}px,${event.clientY - contextMenuHeight}px)`;
contextMenu.hidden = false;
event.preventDefault();
};
})();