Skip to content

Instantly share code, notes, and snippets.

@thihxm
Last active June 5, 2021 13:07
Show Gist options
  • Save thihxm/d29042cdeb01fa68a09ead18d01f397f to your computer and use it in GitHub Desktop.
Save thihxm/d29042cdeb01fa68a09ead18d01f397f to your computer and use it in GitHub Desktop.
Volume & Speed Slider for BB Collaborate
// ==UserScript==
// @name Volume & Speed Slider BB Collaborate
// @namespace thihxm
// @match *://*.bbcollab.com/collab/ui/session/*
// @match *://*.bbcollab.com/guest/*
// @downloadURL https://gist.githubusercontent.com/thihxm/d29042cdeb01fa68a09ead18d01f397f/raw/VolumeSliderBBCollab.js
// @run-at document-idle
// @grant none
// @version 2.0.3
// @author thihxm
// @description Adiciona um slider de volume nas aulas ao vivo do BlackBoard Collaborate e um controle de velocidade nas gravações
// ==/UserScript==
(function() {
'use strict';
const head = document.querySelector('head');
const body = document.querySelector('body');
const style = document.createElement('style');
style.type = 'text/css';
const css = '#custom-bbcollab-volume-slider-wrapper {'+
'position: relative;'+
'}'+
'#custom-bbcollab-volume-slider-value {'+
'position: absolute;'+
'top: -150%;'+
'opacity: 0;'+
'transition: opacity 0.2s linear;'+
'}'+
'#custom-bbcollab-volume-slider-value span {'+
'width: 30px;'+
'height: 24px;'+
'line-height: 24px;'+
'text-align: center;'+
'background: #0575ff;'+
'color: #fff;'+
'font-size: 12px;'+
'display: block;'+
'position: absolute;'+
'left: 50%;'+
'transform: translate(-50%, 0);'+
'border-radius: 6px;'+
'}'+
'#custom-bbcollab-volume-slider-value span:before {'+
'content: "";'+
'position: absolute;'+
'width: 0;'+
'height: 0;'+
'border-top: 10px solid #0575ff;'+
'border-left: 5px solid transparent;'+
'border-right: 5px solid transparent;'+
'top: 100%;'+
'left: 50%;'+
'margin-left: -5px;'+
'margin-top: -1px;'+
'}'+
'#custom-bbcollab-speed-changer {'+
'position: relative;'+
'}'+
'#custom-bbcollab-speed-slider-wrapper {'+
'position: absolute;'+
'z-index: 10;'+
'visibility: visible;'+
'border: 1px solid #cdcdcd;'+
'border-radius: .125rem;'+
'background-color: #fff;'+
'font-size: .875rem;'+
'box-shadow: 0 0 0 4px rgba(38,38,38,.075);'+
'padding: 0;'+
'display: flex;'+
'flex-direction: row;'+
'align-items: center;'+
'height: 1.875rem;'+
'width: 8.875rem;'+
'margin-top: -2rem;'+
'color: #262626;'+
'outline: none!important;'+
'top: calc(50% - 8.875rem / 2);'+
'left: calc(50% - 8.875rem / 2);'+
'transform: rotate(-90deg);'+
'}'+
'#custom-bbcollab-speed-slider-wrapper.isHidden {'+
'visibility: hidden;'+
'display: none;'+
'}'+
'#custom-bbcollab-speed-slider {'+
'transform: translateX(-50%);'+
'left: 50%;'+
'position: relative;'+
'}'+
'#custom-bbcollab-speed-slider-value {'+
'position: absolute;'+
'top: 150%;'+
'opacity: 0;'+
'transition: opacity 0.2s linear;'+
'}'+
'#custom-bbcollab-speed-slider-value span {'+
'width: 40px;'+
'height: 24px;'+
'line-height: 24px;'+
'text-align: center;'+
'background: #0575ff;'+
'color: #fff;'+
'font-size: 12px;'+
'display: block;'+
'position: absolute;'+
'left: 50%;'+
'transform: translate(-50%, 0) rotate(90deg);'+
'border-radius: 6px;'+
'}'+
'#custom-bbcollab-speed-slider-value span:before {'+
'content: "";'+
'position: absolute;'+
'width: 0;'+
'height: 0;'+
'border-top: 10px solid #0575ff;'+
'border-left: 5px solid transparent;'+
'border-right: 5px solid transparent;'+
'top: 50%;'+
'right: 100%;'+
'margin-right: -1px;'+
'margin-top: -5px;'+
'transform: rotate(90deg);'+
'}';
style.appendChild(document.createTextNode(css));
head.appendChild(style);
const waitForEl = (selector, callback) => {
const element = document.querySelector(selector);
if (element) {
callback(element);
} else {
setTimeout(function() {
waitForEl(selector, callback);
}, 100);
}
};
const changeVolume = (volume) => {
document.querySelectorAll('audio').forEach(audioEl => {
audioEl.volume = volume;
});
document.querySelectorAll('video').forEach(videoEl => {
videoEl.volume = volume;
});
}
const handleVolumeChange = (volumeSlider, volumeValueDisplay) => {
volumeSlider.addEventListener('input', e => {
const slider = e.target;
const sliderValue = e.target.value;
const newValue = Number( (sliderValue - slider.min) * 100 / (slider.max - slider.min) );
const newPosition = 10 - (newValue * 0.2);
volumeValueDisplay.innerHTML = `<span>${Math.floor(sliderValue * 100)}</span>`;
volumeValueDisplay.style.left = `calc(${newValue}% + (${newPosition}px))`;
localStorage.setItem('thihxm/bb_volume', sliderValue * 100);
changeVolume(sliderValue);
});
}
const toggleVolumeTooltipEvents = (volumeSlider, volumeValueDisplay) => {
volumeSlider.addEventListener('mouseup', e => {
volumeValueDisplay.style.opacity = 0;
});
volumeSlider.addEventListener('mousedown', e => {
volumeValueDisplay.style.opacity = 1;
});
}
if (body) {
if (window.location.pathname.includes("playback")) {
const playback_volume_slider_selector = '.playback-controls .playback-controls__volume-slider';
waitForEl(playback_volume_slider_selector, playback_volume_slider => {
const speedChangerWrapper = document.createElement('div');
const speedSliderButton = document.createElement('button');
const speedSliderWrapper = document.createElement('div');
const speedSlider = document.createElement('input');
const speedValueDisplay = document.createElement('div');
const buttonIcon = document.createElement('bb-svg-icon');
const buttonTooltip = document.createElement('span');
const buttonTooltipContent = document.createElement('span');
buttonIcon.classList.add('playback-controls__icon');
buttonIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="16px" height="16px"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.38 8.57l-1.23 1.85a8 8 0 0 1-.22 7.58H5.07A8 8 0 0 1 15.58 6.85l1.85-1.23A10 10 0 0 0 3.35 19a2 2 0 0 0 1.72 1h13.85a2 2 0 0 0 1.74-1 10 10 0 0 0-.27-10.44zm-9.79 6.84a2 2 0 0 0 2.83 0l5.66-8.49-8.49 5.66a2 2 0 0 0 0 2.83z"/></svg>';
buttonTooltip.classList.add('tooltip');
buttonTooltip.classList.add('tip-top-right');
buttonTooltip.setAttribute('role', 'tooltip');
buttonTooltipContent.classList.add('tooltip-content');
buttonTooltipContent.innerHTML = 'Velocidade de reprodução';
buttonTooltip.appendChild(buttonTooltipContent);
speedChangerWrapper.id = 'custom-bbcollab-speed-changer';
speedSliderButton.id = 'speed-dropdown-toggle';
speedSliderButton.classList.add('playback-controls__button');
speedSliderButton.classList.add('button');
speedSliderButton.classList.add('has-tooltip');
speedSliderButton.appendChild(buttonIcon);
speedSliderButton.appendChild(buttonTooltip);
speedSliderWrapper.id = 'custom-bbcollab-speed-slider-wrapper';
speedSliderWrapper.classList.add('isHidden');
speedValueDisplay.id = 'custom-bbcollab-speed-slider-value';
speedSlider.id = 'custom-bbcollab-speed-slider';
speedSlider.type = 'range';
speedSlider.min = 0.25;
speedSlider.max = 5;
speedSlider.step = 0.25;
speedSlider.value = 1;
document.addEventListener('click', e => {
if (speedSliderButton.contains(e.target)) {
speedSliderWrapper.classList.toggle('isHidden');
} else if (!speedSliderWrapper.contains(e.target)) {
speedSliderWrapper.classList.add('isHidden');
}
});
speedSlider.addEventListener('input', e => {
const slider = e.target;
const sliderValue = e.target.value;
const newValue = Number( (sliderValue - slider.min) * 100 / (slider.max - slider.min) );
const newPosition = 12 - (newValue * 0.25);
speedValueDisplay.innerHTML = `<span>${sliderValue}x</span>`;
speedValueDisplay.style.left = `calc(${newValue}% + (${newPosition}px))`;
document.querySelector('video').playbackRate = sliderValue;
});
speedSlider.addEventListener('mouseup', e => {
speedValueDisplay.style.opacity = 0;
});
speedSlider.addEventListener('mousedown', e => {
speedValueDisplay.style.opacity = 1;
});
speedSliderWrapper.appendChild(speedSlider);
speedSliderWrapper.appendChild(speedValueDisplay);
speedChangerWrapper.appendChild(speedSliderButton);
speedChangerWrapper.appendChild(speedSliderWrapper);
playback_volume_slider.parentNode.insertBefore(speedChangerWrapper, playback_volume_slider.nextSibling);
});
} else {
const volumeSliderWrapper = document.createElement('div');
const volumeSlider = document.createElement('input');
const volumeValueDisplay = document.createElement('div');
const volume = (localStorage.getItem('thihxm/bb_volume')/100) || 1;
volumeSliderWrapper.id = 'custom-bbcollab-volume-slider-wrapper';
volumeValueDisplay.id = 'custom-bbcollab-volume-slider-value';
volumeSlider.id = 'custom-bbcollab-volume-slider';
volumeSlider.type = 'range'
volumeSlider.min = 0;
volumeSlider.max = 1;
volumeSlider.step = 0.02;
volumeSlider.value = volume;
handleVolumeChange(volumeSlider, volumeValueDisplay);
toggleVolumeTooltipEvents(volumeSlider, volumeValueDisplay);
changeVolume(volume);
volumeSliderWrapper.appendChild(volumeValueDisplay);
volumeSliderWrapper.appendChild(volumeSlider);
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
const addedNodes = mutation.addedNodes;
addedNodes.forEach(newNode => {
const nodeName = newNode.nodeName.toLowerCase();
if (nodeName === 'audio' || nodeName === 'video') {
const volumeSlider = document.querySelector('#custom-bbcollab-volume-slider');
console.log('New Audio/Video Element');
newNode.volume = volume;
handleVolumeChange(volumeSlider, volumeValueDisplay);
toggleVolumeTooltipEvents(volumeSlider, volumeValueDisplay);
}
});
});
var controlsContainer = document.querySelector('.controls-container');
if (controlsContainer && volumeSliderWrapper.parentNode != controlsContainer) {
controlsContainer.appendChild(volumeSliderWrapper);
return;
}
});
const observerConfig = {
childList: true,
subtree: true,
};
document.addEventListener("DOMContentLoaded", () => {
const newValue = Number( (volumeSlider.value - volumeSlider.min) * 100 / (volumeSlider.max - volumeSlider.min) );
const newPosition = 10 - (newValue * 0.2);
volumeValueDisplay.innerHTML = `<span>${Math.floor(volumeSlider.value * 100)}</span>`;
volumeValueDisplay.style.left = `calc(${newValue}% + (${newPosition}px))`;
});
observer.observe(body, observerConfig);
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment