Last active
September 19, 2024 12:30
-
-
Save Chaosmeister/918a8b75b1c43e2ef9daa5cab4d347b7 to your computer and use it in GitHub Desktop.
more efficient rvrb layout
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 RVRB Relayout | |
// @namespace https://app.rvrb.one/ | |
// @version 1.11 | |
// @description RVRB relayout | |
// @author Tomas Dittmann, Nicola Bosco | |
// @match https://app.rvrb.one/* | |
// @icon https://app.rvrb.one/favicon-32x32.png | |
// @grant none | |
// ==/UserScript== | |
///// CHANGELOG | |
//// 1.11 | |
// autodope after 1 and song-length/2 seconds have passed | |
//// 1.10 | |
// use mutationobserver for autodope | |
//// 1.9 | |
// fix autodope loop | |
//// 1.8 | |
// adjust to rvrb v1.10 | |
// move menu text below buttons | |
// use visibility attribute instead of display to fix menu button positions | |
// add setting to hide menutitles | |
// fix custommenu position | |
// use rvrb icon | |
// use rvrb styles | |
//// 1.7 | |
// adjust to rvrb v1.9 | |
//// 1.6 | |
// call colorizeBackground on start-up | |
//// 1.5 | |
// cleanup | |
// refactor menuitem code into separate function | |
// add background styling by Kino | |
//// 1.4 | |
// add Changelog | |
// move checkboxes into separate menu | |
// this will allow adding features more easily | |
(function() { | |
'use strict'; | |
// INTERNAL DATA / FUNCTIONS // | |
var Style1; | |
var Style2; | |
var Style3; | |
function convert(input) { | |
var parts = input.split(':'), | |
minutes = +parts[0], | |
seconds = +parts[1]; | |
return (minutes * 60 + seconds); | |
} | |
function waitForEl(selector) { | |
return new Promise((resolve) => { | |
if (document.querySelector(selector)) { | |
return resolve(document.querySelector(selector)); | |
} | |
const observer = new MutationObserver(() => { | |
if (document.querySelector(selector)) { | |
resolve(document.querySelector(selector)); | |
observer.disconnect(); | |
} | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true, | |
attributes: true, | |
}); | |
}); | |
} | |
function RegisterTrackChange() { | |
const observer = new MutationObserver(() => { | |
dope(false); | |
}); | |
observer.observe(document.body.querySelector("#trackTitle"), { | |
childList: true, | |
subtree: true, | |
attributes: true, | |
}); | |
} | |
function dope(immediately) | |
{ | |
if (typeof (Storage) !== "undefined") { | |
if (localStorage.getItem("autodope")) { | |
const btn = document.body.querySelector(".section-content.floating.reactions > .section-actions > .action"); | |
if (immediately) | |
{ | |
if (btn.className.indexOf("active") < 0){ | |
btn.click(); | |
} | |
} | |
else | |
{ | |
// dope sometime after half the tracklength + 1 seconds | |
var halfLengthInMilliseconds = ((convert(document.body.querySelector(".trackLength").innerText)/2)+1)*1000; | |
setTimeout(() => { | |
if (btn.className.indexOf("active") < 0){ | |
btn.click(); | |
} | |
}, Math.floor(Math.random() * halfLengthInMilliseconds)); | |
} | |
} | |
} | |
} | |
function colorizeScrollbar() | |
{ | |
if (typeof (Storage) !== "undefined") { | |
if (localStorage.getItem("colorizescrollbar")) { | |
Style1 = addGlobalStyle(` | |
div ::-webkit-scrollbar-thumb { | |
background: linear-gradient(to bottom, var(--secondary-album-palette), var(--primary-album-palette)) | |
}`); | |
Style2 = addGlobalStyle(` | |
div ::-webkit-scrollbar-thumb:window-inactive { | |
background: linear-gradient(to bottom, var(--secondary-album-palette), var(--primary-album-palette)) | |
}`); | |
} else { | |
if (Style1) | |
{ | |
Style1.remove(); | |
} | |
if (Style2) | |
{ | |
Style2.remove(); | |
} | |
} | |
} | |
} | |
function colorizeBackground() | |
{ | |
if (typeof (Storage) !== "undefined") { | |
if (localStorage.getItem("colorizebackground")) { | |
Style3 = addGlobalStyle(` | |
.section-content.fixed:hover, .section-content.scrollable:hover { | |
background-color: rgba(0,0,0,.4)!important; | |
} | |
@property --albumColor { | |
syntax: '<color>'; | |
initial-value: black; | |
inherits: false; | |
} | |
@property --albumColorSecondary { | |
syntax: '<color>'; | |
initial-value: black; | |
inherits: false; | |
} | |
@property --black { | |
syntax: '<color>'; | |
initial-value: black; | |
inherits: false; | |
} | |
#App, #MobileApp { | |
--albumColorSecondary: var(--secondary-album-palette); | |
background-image: linear-gradient(-45deg, var(--albumColorSecondary), var(--black) 85%)!important; | |
transition: --albumColorSecondary 1s; | |
}`); | |
} else { | |
if (Style3) | |
{ | |
Style3.remove(); | |
} | |
} | |
} | |
} | |
function hidemenutitles() | |
{ | |
if (typeof (Storage) !== "undefined") { | |
var SideMenu = document.querySelector('#SideMenu'); | |
if (localStorage.getItem("hidemenutitles")) { | |
SideMenu.querySelectorAll(".nav-label").forEach(item=>{ | |
item.style.visibility = "hidden"; | |
}); | |
UpdateHeight(50); | |
} | |
else | |
{ | |
SideMenu.querySelectorAll(".nav-label").forEach(item=>{ | |
item.style.visibility = "visible"; | |
}); | |
UpdateHeight(65); | |
} | |
} | |
} | |
function addGlobalStyle(css) | |
{ | |
var node = document.createElement("style"); | |
node.type = "text/css"; | |
node.appendChild(document.createTextNode(css)); | |
var heads = document.getElementsByTagName("head"); | |
if (heads.length > 0) { | |
heads[0].appendChild(node); | |
} else { | |
// no head yet, stick it whereever | |
document.documentElement.appendChild(node); | |
} | |
return node; | |
} | |
function addCheckbox(Title, Id, OnChange) | |
{ | |
var Element = document.createElement("div"); | |
Element.classList.add("nav-button"); | |
Element.style.display = "flex"; | |
Element.style.justifyContent = "space-between"; | |
Element.style.flexDirection = "row"; | |
Element.innerHTML = '<label for="ID' + Id + '">' + Title + '</label>'; | |
var CheckBox = document.createElement("input"); | |
CheckBox.type = "checkbox"; | |
CheckBox.id = "ID" + Id; | |
CheckBox.style.marginLeft = "5px" | |
if (typeof (Storage) !== "undefined") { | |
if (localStorage.getItem(Id)) { | |
CheckBox.checked = true; | |
} | |
} | |
CheckBox.addEventListener('change', (event) => { | |
if (typeof (Storage) !== "undefined") { | |
if (event.currentTarget.checked) { | |
localStorage.setItem(Id, 'on'); | |
} else { | |
localStorage.removeItem(Id); | |
} | |
} | |
}); | |
CheckBox.addEventListener('change', OnChange); | |
Element.appendChild(CheckBox); | |
return Element; | |
} | |
function UpdateHeight(Height) | |
{ | |
var App = document.querySelector('#App'); | |
App.style.height = 'calc(100% - ' + Height + 'px)'; | |
var SideMenu = document.querySelector('#SideMenu'); | |
SideMenu.style.height = Height + "px"; | |
var CustomMenu = SideMenu.querySelector('#CustomMenu'); | |
CustomMenu.style.marginTop = Height - CustomMenu.previousElementSibling.clientHeight + "px"; | |
} | |
// Main functions | |
function updateLayout() { | |
///// Re-Layout ///// | |
// remove the SideMenu open button | |
document.querySelector('.toggle-button').remove() | |
// move SideMenu to top | |
var App = document.querySelector('#App'); | |
var SideMenu = document.querySelector('#SideMenu'); | |
App.before(SideMenu); | |
// fix SideMenu Layout | |
SideMenu.style.flexDirection = 'row'; | |
SideMenu.style.width = 'auto'; | |
// remove Account button margins and fix to the right border | |
var Account = SideMenu.querySelector('[title="Account"]'); | |
Account.style.marginTop = 'unset'; | |
Account.style.marginLeft = 'auto'; | |
// show complete text in SideMenu; | |
document.querySelectorAll('.ellipses').forEach(item=>{ | |
item.style.overflow = 'unset'; | |
}); | |
SideMenu.querySelectorAll(".nav-button").forEach(item=>{ | |
item.style.flexDirection = 'column'; | |
item.style.alignItems = 'center'; | |
}); | |
// move the ChatView to center | |
var Chatview = document.querySelector('#ChatView'); | |
var UserView = document.querySelector('#UserView'); | |
Chatview.after(UserView); | |
} | |
function CreateCustomMenu(){ | |
var Menu = document.createElement("div"); | |
Menu.style.visibility = "hidden"; | |
Menu.style.background = "#000" | |
Menu.style.zIndex = "100"; | |
Menu.style.flexDirection = "column"; | |
Menu.id = "CustomMenu"; | |
var MenuButtonText = document.createElement("div"); | |
MenuButtonText.innerHTML = "RE-LAYOUT" | |
MenuButtonText.classList.add("nav-label"); | |
var MenuButtonBox = document.createElement("div"); | |
MenuButtonBox.classList.add("nav-icon"); | |
var MenuButtonIcon = document.createElement("i"); | |
MenuButtonIcon.classList.add("icon"); | |
MenuButtonIcon.classList.add("rvrb-settings"); | |
MenuButtonBox.appendChild(MenuButtonIcon); | |
var MenuButton = document.createElement("div"); | |
MenuButton.appendChild(MenuButtonBox); | |
MenuButton.appendChild(MenuButtonText); | |
MenuButton.classList.add("nav-button"); | |
MenuButton.style.flexDirection = "column"; | |
MenuButton.style.alignItems = "center"; | |
MenuButton.addEventListener("click", function() { | |
if (event.currentTarget !== event.target) { | |
if (Menu.style.visibility === "hidden") { | |
Menu.style.visibility = "visible"; | |
} | |
else | |
{ | |
Menu.style.visibility = "hidden"; | |
} | |
} | |
}); | |
var CustomMenu = document.createElement("div"); | |
CustomMenu.style.display = "flex"; | |
CustomMenu.style.flexDirection = "column"; | |
CustomMenu.appendChild(MenuButton); | |
CustomMenu.appendChild(Menu); | |
var SideMenu = document.querySelector('#SideMenu'); | |
var Account = SideMenu.querySelector('[title="Account"]'); | |
Account.before(CustomMenu); | |
Menu.appendChild(addCheckbox("Autodope", "autodope", (event) => { | |
dope(true); | |
})); | |
Menu.appendChild(addCheckbox("Colorize scrollbar","colorizescrollbar", (event) => { | |
colorizeScrollbar(); | |
})); | |
Menu.appendChild(addCheckbox("Colorize background","colorizebackground", (event) => { | |
colorizeBackground(); | |
})); | |
Menu.appendChild(addCheckbox("Hide menu titles","hidemenutitles", (event) => { | |
hidemenutitles(); | |
})); | |
} | |
// wait for all elements to load before applying all the patches | |
waitForEl("#ChatView").then(() => { | |
updateLayout(); | |
CreateCustomMenu(); | |
// apply custom features | |
dope(true); | |
colorizeScrollbar(); | |
colorizeBackground(); | |
hidemenutitles(); | |
// register autodope on trackchange | |
RegisterTrackChange(); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment