// ==UserScript==
// @name Custom Native HTML5 Player with Shortcuts
// @namespace https://gist.github.com/narcolepticinsomniac
// @version 1.9
// @description Custom html5 player with shortcuts and v.redd.it videos with audio
// @author narcolepticinsomniac
// @include *
// @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
// @run-at document-start
// @grant GM.xmlHttpRequest
// @connect v.redd.it
// ==/UserScript==
let imagusAudio;
let audioSync;
let audioError;
let ytID;
let ytTimeChecked;
const $ = document.querySelector.bind(document);
const $$ = document.querySelectorAll.bind(document);
const newEl = document.createElement.bind(document);
const settings = {
// delay to hide contols and cursor if inactive (set to 3000 milliseconds)
hideControls: 3000,
// delay for fullscreen double-click (set to 300 milliseconds)
clickDelay: 300,
// right-click delay to match imagus user setting (set to 0 milliseconds)
imagusStickyDelay: 0,
// right/left arrows keys or inner skip buttons (set to 10 seconds)
skipNormal: 10,
// Shift + Arrow keys or outer skip buttons (set to 30 seconds)
skipShift: 30,
// Ctrl + Arrow keys skip (set to 1 minute)
skipCtrl: 1,
};
const shortcutFuncs = {
toggleCaptions: v => {
const validTracks = [];
for (let i = 0; i < v.textTracks.length; ++i) {
const tt = v.textTracks[i];
if (tt.mode === 'showing') {
tt.mode = 'disabled';
if (v.textTracks.addEventListener) {
// If text track event listeners are supported
// (they are on the most recent Chrome), add
// a marker to remember the old track. Use a
// listener to delete it if a different track
// is selected.
v.cbhtml5vsLastCaptionTrack = tt.label;
function cleanup(e) {
for (let i = 0; i < v.textTracks.length; ++i) {
const ott = v.textTracks[i];
if (ott.mode === 'showing') {
delete v.cbhtml5vsLastCaptionTrack;
v.textTracks.removeEventListener('change', cleanup);
return;
}
}
}
v.textTracks.addEventListener('change', cleanup);
}
return;
} else if (tt.mode !== 'hidden') {
validTracks.push(tt);
}
}
// If we got here, none of the tracks were selected.
if (validTracks.length === 0) {
return true; // Do not prevent default if no UI activated
}
// Find the best one and select it.
validTracks.sort((a, b) => {
if (v.cbhtml5vsLastCaptionTrack) {
const lastLabel = v.cbhtml5vsLastCaptionTrack;
if (a.label === lastLabel && b.label !== lastLabel) {
return -1;
} else if (b.label === lastLabel && a.label !== lastLabel) {
return 1;
}
}
const aLang = a.language.toLowerCase();
const bLang = b.language.toLowerCase();
const navLang = navigator.language.toLowerCase();
if (aLang === navLang && bLang !== navLang) {
return -1;
} else if (bLang === navLang && aLang !== navLang) {
return 1;
}
const aPre = aLang.split('-')[0];
const bPre = bLang.split('-')[0];
const navPre = navLang.split('-')[0];
if (aPre === navPre && bPre !== navPre) {
return -1;
} else if (bPre === navPre && aPre !== navPre) {
return 1;
}
return 0;
})[0].mode = 'showing';
},
togglePlay: v => {
v.paused ? v.play() : v.pause();
},
toStart: v => {
v.currentTime = 0;
},
toEnd: v => {
v.currentTime = v.duration;
},
skipLeft: (v, key, shift, ctrl) => {
if (shift) {
v.currentTime -= settings.skipShift;
} else if (ctrl) {
v.currentTime -= settings.skipCtrl;
} else {
v.currentTime -= settings.skipNormal;
}
},
skipRight: (v, key, shift, ctrl) => {
if (shift) {
v.currentTime += settings.skipShift;
} else if (ctrl) {
v.currentTime += settings.skipCtrl;
} else {
v.currentTime += settings.skipNormal;
}
},
increaseVol: v => {
if (audioError) return;
if (v.nextSibling.querySelector('volume.disabled')) {
v.volume = 0;
return;
}
const increase = (v.volume + 0.1).toFixed(1);
if (v.muted) {
v.muted = !v.muted;
v.volume = 0.1;
} else {
v.volume <= 0.9 ? v.volume = increase : v.volume = 1;
}
},
decreaseVol: v => {
if (audioError) return;
if (v.nextSibling.querySelector('volume.disabled')) {
v.volume = 0;
return;
}
const decrease = (v.volume - 0.1).toFixed(1);
v.volume >= 0.1 ? v.volume = decrease : v.volume = 0;
},
toggleMute: v => {
v.muted = !v.muted;
if (audioSync) imagusAudio.muted = v.muted;
},
toggleFS: v => {
if (document.fullscreenElement) {
document.exitFullscreen();
v.parentElement.classList.remove('native-fullscreen');
} else {
v.parentElement.classList.add('native-fullscreen');
v.parentElement.requestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
}
},
reloadVideo: v => {
const currTime = v.currentTime;
v.load();
v.currentTime = currTime;
},
slowOrPrevFrame: (v, key, shift) => {
if (shift) { // Less-Than
v.currentTime -= 1 / 60;
} else { // Comma
if (v.playbackRate >= 0.1) {
const decrease = (v.playbackRate - 0.1).toFixed(2);
const rate = v.nextSibling.querySelector('rate');
v.playbackRate = decrease;
rate.textContent = `${v.playbackRate}x`;
if (v.playbackRate !== 1) {
rate.setAttribute('data-current-rate', `${v.playbackRate}x`);
}
if (v.playbackRate === 0.9) {
v.classList.add('playback-rate-decreased');
} else if (v.playbackRate === 1.1) {
v.classList.add('playback-rate-increased');
} else if (v.playbackRate === 1) {
v.classList.remove('playback-rate-decreased');
v.classList.remove('playback-rate-increased');
rate.removeAttribute('data-current-rate');
}
} else {
v.playbackRate = 0;
}
if (audioSync) imagusAudio.playbackRate = v.playbackRate;
}
},
fastOrNextFrame: (v, key, shift) => {
if (shift) { // Greater-Than
v.currentTime += 1 / 60;
} else { // Period
if (v.playbackRate <= 15.9) {
const increase = (v.playbackRate += 0.1).toFixed(2);
const rate = v.nextSibling.querySelector('rate');
v.playbackRate = increase;
rate.textContent = `${v.playbackRate}x`;
if (v.playbackRate !== 1) {
rate.setAttribute('data-current-rate', `${v.playbackRate}x`);
}
if (v.playbackRate === 0.9) {
v.classList.add('playback-rate-decreased');
} else if (v.playbackRate === 1.1) {
v.classList.add('playback-rate-increased');
} else if (v.playbackRate === 1) {
v.classList.remove('playback-rate-decreased');
v.classList.remove('playback-rate-increased');
rate.removeAttribute('data-current-rate');
}
} else {
v.playbackRate = 16;
}
if (audioSync) imagusAudio.playbackRate = v.playbackRate;
}
},
normalSpeed: v => { // ?
v.playbackRate = v.defaultPlaybackRate;
if (audioSync) imagusAudio.playbackRate = v.playbackRate;
v.classList.remove('playback-rate-decreased');
v.classList.remove('playback-rate-increased');
v.nextSibling.querySelector('rate').textContent = '1x';
v.nextSibling.querySelector('rate').removeAttribute('data-current-rate');
},
toPercentage: (v, key) => {
v.currentTime = (v.duration * (key - 48)) / 10.0;
},
};
const keyFuncs = {
32: shortcutFuncs.togglePlay, // Space
75: shortcutFuncs.togglePlay, // K
35: shortcutFuncs.toEnd, // End
48: shortcutFuncs.toStart, // 0
36: shortcutFuncs.toStart, // Home
37: shortcutFuncs.skipLeft, // Left arrow
74: shortcutFuncs.skipLeft, // J
39: shortcutFuncs.skipRight, // Right arrow
76: shortcutFuncs.skipRight, // L
38: shortcutFuncs.increaseVol, // Up arrow
40: shortcutFuncs.decreaseVol, // Down arrow
77: shortcutFuncs.toggleMute, // M
70: shortcutFuncs.toggleFS, // F
67: shortcutFuncs.toggleCaptions, // C
82: shortcutFuncs.reloadVideo, // R
188: shortcutFuncs.slowOrPrevFrame, // Comma or Less-Than
190: shortcutFuncs.fastOrNextFrame, // Period or Greater-Than
191: shortcutFuncs.normalSpeed, // Forward slash or ?
49: shortcutFuncs.toPercentage, // 1
50: shortcutFuncs.toPercentage, // 2
51: shortcutFuncs.toPercentage, // 3
52: shortcutFuncs.toPercentage, // 4
53: shortcutFuncs.toPercentage, // 5
54: shortcutFuncs.toPercentage, // 6
55: shortcutFuncs.toPercentage, // 7
56: shortcutFuncs.toPercentage, // 8
57: shortcutFuncs.toPercentage, // 9
};
function customPlayer(v) {
let videoWrapper;
let savedTimeKey;
let mouseDown;
let isPlaying;
let isSeeking;
let earlyXposPercent;
let preventMouseMove;
let controlsTimeout;
let imagusMouseTimeout;
let imagusVid;
let muteTillSync;
let loaded;
let error;
let elToFocus;
let target;
let clickCount = 0;
let repeat = 0;
const directVideo = /video/.test(document.contentType) &&
document.body.firstElementChild === v;
const controls = newEl('controls');
const imagus = v.classList.contains('imagus');
if (imagus && !imagusVid) {
imagusVid = v;
imagusAudio = newEl('video');
imagusAudio.preload = 'auto';
imagusAudio.autoplay = 'true';
imagusAudio.className = 'imagus imagus-audio';
imagusAudio.style = 'display: none!important;';
imagusVid.parentElement.insertBefore(imagusAudio, imagusVid);
}
if (directVideo) {
elToFocus = document.body;
self === top ? document.body.classList.add('direct-video-top-level') :
document.body.classList.add('direct-video-embed');
} else {
elToFocus = v;
videoWrapper = newEl('videowrapper');
v.parentNode.insertBefore(videoWrapper, v);
videoWrapper.appendChild(v);
if (!imagus) {
const compStyles = getComputedStyle(v);
const position = compStyles.getPropertyValue('position');
const zIndex = compStyles.getPropertyValue('z-index');
if (position === 'absolute') {
videoWrapper.style.setProperty('--wrapper-position', `${position}`);
}
if (zIndex !== 'auto') {
controls.style.setProperty('--controls-z-index', `calc(${zIndex} + 1)`);
}
}
}
v.parentNode.insertBefore(controls, v.nextSibling);
const playButton = newEl('btn');
playButton.className = 'toggle-play';
controls.appendChild(playButton);
const beginButton = newEl('btn');
beginButton.className = 'begin';
controls.appendChild(beginButton);
const skipLongLeft = newEl('btn');
skipLongLeft.className = 'skip-long left';
controls.appendChild(skipLongLeft);
const skipShortLeft = newEl('btn');
skipShortLeft.className = 'skip-short left';
controls.appendChild(skipShortLeft);
const skipShortRight = newEl('btn');
skipShortRight.className = 'skip-short right';
controls.appendChild(skipShortRight);
const skipLongRight = newEl('btn');
skipLongRight.className = 'skip-long right';
controls.appendChild(skipLongRight);
const timelineWrapper = newEl('timelinewrapper');
controls.appendChild(timelineWrapper);
const currentTime = newEl('currenttime');
currentTime.textContent = '0:00';
timelineWrapper.appendChild(currentTime);
const timeline = newEl('timeline');
timelineWrapper.appendChild(timeline);
const timeBar = newEl('timebar');
timeline.appendChild(timeBar);
const timeBuffer = newEl('timebuffer');
timeBar.appendChild(timeBuffer);
const timeProgress = newEl('timeprogress');
timeBar.appendChild(timeProgress);
const timeSlider = newEl('input');
timeSlider.type = 'range';
timeSlider.value = 0;
timeSlider.min = 0;
timeSlider.max = 100;
timeSlider.step = 0.01;
timeSlider.textContent = '';
timeline.appendChild(timeSlider);
const timeTooltip = newEl('timetooltip');
timeTooltip.className = 'hidden';
timeline.appendChild(timeTooltip);
const preview = newEl('preview');
timeTooltip.appendChild(preview);
const timeText = newEl('timetext');
timeTooltip.appendChild(timeText);
timeText.textContent = '-:-';
const totalTime = newEl('totaltime');
totalTime.textContent = '-:-';
timelineWrapper.appendChild(totalTime);
const rateDecrease = newEl('btn');
rateDecrease.className = 'rate-decrease';
controls.appendChild(rateDecrease);
const rate = newEl('rate');
rate.textContent = '1x';
controls.appendChild(rate);
const rateIncrease = newEl('btn');
rateIncrease.className = 'rate-increase';
controls.appendChild(rateIncrease);
const volume = newEl('volume');
controls.appendChild(volume);
const volumeBar = newEl('volumebar');
volume.appendChild(volumeBar);
const volumeTrail = newEl('volumetrail');
volumeBar.appendChild(volumeTrail);
const volumeSlider = newEl('input');
volumeSlider.type = 'range';
volumeSlider.min = 0;
volumeSlider.max = 1;
volumeSlider.step = 0.01;
volumeSlider.textContent = '';
volume.appendChild(volumeSlider);
const volumeTooltip = newEl('volumetooltip');
volumeTooltip.className = 'hidden';
volumeTooltip.textContent = '0%';
volume.appendChild(volumeTooltip);
const muteButton = newEl('btn');
muteButton.className = 'mute';
controls.appendChild(muteButton);
const expandButton = newEl('btn');
expandButton.className = 'expand';
controls.appendChild(expandButton);
v.classList.remove('custom-native-player-hidden');
if (v.querySelector('source')) v.classList.add('contains-source');
if (videoWrapper) enforcePosition();
volumeValues();
v.onloadedmetadata = e => {
loaded = true;
shortcutFuncs.normalSpeed(v);
savedTimeKey = `${location.pathname}${location.search}${v.duration}`;
const savedTime = localStorage.getItem(savedTimeKey);
if (timeSlider.value === '0') {
if (savedTime) v.currentTime = savedTime;
} else if (earlyXposPercent) {
const time = (earlyXposPercent * v.duration) / 100;
v.currentTime = time;
}
currentTime.textContent = formatTime(v.currentTime);
totalTime.textContent = formatTime(v.duration);
v.classList.remove('disabled');
sliderValues(e);
};
v.onloadeddata = () => {
const imagusVreddit = /v(cf)?\.redd\.it/.test(v.src);
const vHasAudio = hasAudio(v);
if (!vHasAudio && !imagusVreddit) {
v.classList.add('muted');
volumeSlider.value = 0;
muteButton.classList.add('disabled');
volume.classList.add('disabled');
} else if (vHasAudio && !imagusVreddit) {
if (v.volume && !v.muted) v.classList.remove('muted');
volumeValues();
if (volume.classList.contains('disabled')) {
muteButton.classList.remove('disabled');
volume.classList.remove('disabled');
}
}
elToFocus.focus({preventScroll: true});
if (v.duration <= settings.skipNormal) {
skipShortLeft.classList.add('disabled');
skipShortRight.classList.add('disabled');
} else {
skipShortLeft.classList.remove('disabled');
skipShortRight.classList.remove('disabled');
}
if (v.duration <= settings.skipShift) {
skipLongLeft.classList.add('disabled');
skipLongRight.classList.add('disabled');
} else {
skipLongLeft.classList.remove('disabled');
skipLongRight.classList.remove('disabled');
}
if (v.paused) {
v.classList.add('paused');
if (videoWrapper) videoWrapper.classList.add('paused');
}
if (imagus) v.currentTime = 0;
};
v.oncanplay = () => {
v.oncanplay = null;
if (!loaded) {
v.load();
console.log('Custom native player reloaded');
}
};
v.onseeked = () => {
styleBuffer();
setTimeout(styleBuffer, 500);
};
v.onprogress = () => {
styleBuffer();
setTimeout(styleBuffer, 500);
};
v.ontimeupdate = e => {
if (v.readyState > 0) {
if (v.duration > 0 && !mouseDown) {
sliderValues(e);
totalTime.textContent = formatTime(v.duration);
if (!imagus && savedTimeKey) localStorage.setItem(savedTimeKey, v.currentTime);
}
}
};
v.onvolumechange = e => {
if (audioError) return;
if (audioSync) imagusAudio.volume = v.volume;
if (v.muted || !v.volume) {
v.classList.add('muted');
volumeSlider.value = 0;
volumeTrail.style.width = '0';
localStorage.setItem('videomuted', 'true');
} else {
v.classList.remove('muted');
sliderValues(e);
v.volume > 0.1 ? localStorage.setItem('videovolume', v.volume) :
localStorage.setItem('videovolume', 0.1);
localStorage.setItem('videomuted', 'false');
}
};
v.onplay = () => {
if (v === imagusVid && audioSync) imagusAudio.play();
v.classList.remove('paused');
if (videoWrapper) videoWrapper.classList.remove('paused');
v.classList.add('playing');
};
v.onpause = () => {
if (v === imagusVid && audioSync) imagusAudio.pause();
if (!isSeeking) {
v.classList.remove('playing');
v.classList.add('paused');
if (videoWrapper) videoWrapper.classList.add('paused');
}
};
v.onended = () => {
if (localStorage.getItem(savedTimeKey)) localStorage.removeItem(savedTimeKey);
savedTimeKey = false;
};
v.onemptied = () => {
if (v === imagusVid) {
const vPP = v.parentNode.parentNode;
if (imagusAudio.getAttribute('src') &&
/v(cf)?\.redd\.it/.test(imagusAudio.src)) {
audioSync = false;
audioError = false;
imagusAudio.pause();
imagusAudio.removeAttribute('src');
imagusAudio.load();
imagusAudio.removeAttribute('loop');
}
if (v.src !== '') {
if (/\.(mp3|m4a)/.test(v.src)) {
vPP.classList.add('audio-only');
}
if (/v(cf)?\.redd\.it/.test(v.src)) {
const prefix = v.src.split('DASH')[0].replace('vcf.', 'v.');
const audioSrc = `${prefix}DASH_AUDIO_128.mp4`;
GM.xmlHttpRequest({
method: 'GET',
url: audioSrc,
onload: xhr => {
imagusAudio.src = xhr.status >= 200 && xhr.status < 300 ? audioSrc : `${prefix}audio`;
},
onerror: () => {
imagusAudio.src = `${prefix}audio`;
},
});
if (!imagusAudio.muted) {
muteTillSync = true;
imagusAudio.muted = true;
}
if (imagusVid.hasAttribute('loop')) imagusAudio.setAttribute('loop', 'true');
}
vPP.classList.add('imagus-video-wrapper');
window.addEventListener('click', imagusClick, true);
document.addEventListener('keyup', imagusKeys, true);
document.addEventListener('mousedown', imagusMouseDown, true);
document.addEventListener('mouseup', imagusMouseUp, true);
} else {
audioSync = false;
audioError = false;
imagusAudio.pause();
imagusAudio.removeAttribute('src');
imagusAudio.load();
imagusAudio.removeAttribute('loop');
vPP.removeAttribute('class');
timeTooltip.classList.add('hidden');
window.removeEventListener('click', imagusClick, true);
document.removeEventListener('keyup', imagusKeys, true);
document.removeEventListener('mousedown', imagusMouseDown, true);
document.removeEventListener('mouseup', imagusMouseUp, true);
}
}
};
v.onerror = () => {
error = true;
elToFocus.blur();
v.classList.add('disabled');
};
v.onmousedown = e => {
if (error && e.button !== 2) return;
e.stopPropagation();
e.stopImmediatePropagation();
if (e.button === 0) {
clickCount++;
const checkState = v.paused;
if (clickCount === 1) {
setTimeout(() => {
if (clickCount === 1) {
// avoid conflicts with existing click listeners
const recheckState = v.paused;
if (checkState === recheckState) shortcutFuncs.togglePlay(v);
} else {
shortcutFuncs.toggleFS(v);
}
clickCount = 0;
}, settings.clickDelay);
}
} else if (e.button === 2) {
window.addEventListener('contextmenu', preventHijack, true);
}
};
v.onmouseup = e => {
if (e.button === 2) {
setTimeout(() => {
window.removeEventListener('contextmenu', preventHijack, true);
}, 100);
}
if (error) elToFocus.blur();
};
v.onmousemove = () => {
controlsTimeout ? clearTimeout(controlsTimeout) :
v.classList.add('active');
if (videoWrapper) videoWrapper.classList.add('active');
controlsTimeout = setTimeout(() => {
controlsTimeout = false;
v.classList.remove('active');
if (videoWrapper) videoWrapper.classList.remove('active');
}, settings.hideControls);
};
new ResizeObserver(compactControls).observe(v);
controls.onmousedown = e => {
if (e.button > 0) return;
target = e.target;
};
controls.onmouseup = () => {
if (error) return;
elToFocus.focus({preventScroll: true});
target = null;
};
timeSlider.onmousemove = e => sliderValues(e);
timeSlider.oninput = e => sliderValues(e);
timeSlider.onmousedown = e => {
if (e.button > 0) return;
mouseDown = true;
isSeeking = true;
if (timeTooltip.classList.contains('hidden')) sliderValues(e);
if (v.readyState > 0) {
if (!v.paused) {
isPlaying = true;
v.pause();
} else {
isPlaying = false;
}
}
};
timeSlider.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
mouseDown = false;
isSeeking = false;
if (v.readyState > 0) {
sliderValues(e);
if (isPlaying) {
v.play();
isPlaying = false;
}
}
};
volumeSlider.onmousemove = e => sliderValues(e);
volumeSlider.oninput = e => {
if (v.muted) shortcutFuncs.toggleMute(v);
sliderValues(e);
};
muteButton.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
const lastVolume = localStorage.getItem('videovolume');
if (v.muted || v.volume) shortcutFuncs.toggleMute(v);
v.volume = lastVolume;
if (audioSync) imagusAudio.muted = v.muted;
};
playButton.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.togglePlay(v);
};
skipShortLeft.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.skipLeft(v);
};
skipShortRight.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.skipRight(v);
};
skipLongLeft.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
v.currentTime -= settings.skipShift;
};
skipLongRight.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
v.currentTime += settings.skipShift;
};
beginButton.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
v.currentTime = 0;
timeSlider.value = 0;
timeProgress.style.width = '0';
currentTime.textContent = '0:00';
};
rateDecrease.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.slowOrPrevFrame(v);
};
rateIncrease.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.fastOrNextFrame(v);
};
rate.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.normalSpeed(v);
};
rate.onmouseenter = () => {
rate.textContent = '1x?';
};
rate.onmouseleave = () => {
const currentRate = rate.getAttribute('data-current-rate');
if (currentRate) rate.textContent = currentRate;
};
expandButton.onmouseup = e => {
if (e.button > 0 || e.target !== target) return;
shortcutFuncs.toggleFS(v);
};
// exiting fullscreen by escape key or other browser provided method
document.onfullscreenchange = () => {
if (!document.fullscreenElement) {
const nativeFS = $('.native-fullscreen');
if (nativeFS) nativeFS.classList.remove('native-fullscreen');
}
};
if (imagusVid) {
imagusAudio.onloadedmetadata = () => {
audioSync = true;
if (v.hasAttribute('autoplay')) imagusAudio.play();
};
imagusAudio.onloadeddata = () => {
if (v.volume && !v.muted) v.classList.remove('muted');
volumeValues(v);
if (volume.classList.contains('disabled')) {
muteButton.classList.remove('disabled');
volume.classList.remove('disabled');
}
};
imagusAudio.onended = () => {
imagusAudio.currentTime = 0;
if (imagusVid.hasAttribute('loop')) imagusAudio.play();
};
imagusAudio.onerror = () => {
audioError = true;
v.classList.add('muted');
volumeSlider.value = 0;
muteButton.classList.add('disabled');
volume.classList.add('disabled');
};
}
if (directVideo) {
v.removeAttribute('tabindex');
document.body.setAttribute('tabindex', '0');
document.addEventListener('keydown', docHandleKeyDown, true);
document.addEventListener('keypress', docHandleKeyOther, true);
document.addEventListener('keyup', docHandleKeyOther, true);
} else {
v.addEventListener('keydown', handleKeyDown, false);
v.addEventListener('keypress', handleKeyOther, false);
v.addEventListener('keyup', handleKeyOther, false);
}
function sliderValues(e) {
let slider;
let xPosition;
const vid = audioSync ? imagusAudio && v : v;
const eType = e && e.type;
const eTime = eType === 'timeupdate';
const eVolume = eType === 'volumechange';
const eMeta = eType === 'loadedmetadata';
const eData = eType === 'loadeddata';
const eInput = eType === 'input';
const eMouseUp = eType === 'mouseup';
const eMouseMove = eType === 'mousemove';
const eMouseDown = eType === 'mousedown';
if (eMeta || eTime || eVolume || eData || !e) {
slider = eMeta || eTime ? timeSlider : volumeSlider;
} else {
slider = e.target;
}
const tooltip = slider.nextSibling;
const timeTarget = slider === timeSlider;
const sliderWidth = slider.clientWidth;
const halfSlider = sliderWidth / 2;
const slider14ths = halfSlider / 7;
const eX = e && e.offsetX;
const start7 = eX <= 7;
const end7 = eX >= sliderWidth - 7;
if (eMouseMove || eMouseDown) {
if (start7 || end7) {
xPosition = start7 ? 0 : sliderWidth;
} else {
xPosition = eX < halfSlider ? (eX + (-7 + (eX / slider14ths))).toFixed(1) :
(eX + ((eX - halfSlider) / slider14ths)).toFixed(1);
}
}
if (eMeta || eTime || eVolume || eData || !e) {
xPosition = eMeta || eTime ?
((((100 / v.duration) * v.currentTime) * sliderWidth) / 100).toFixed(1) :
(v.volume * sliderWidth).toFixed(1);
}
if (eTime && e.target === imagusVid && audioSync) {
if (imagusVid.currentTime - imagusAudio.currentTime >= 0.1 ||
imagusVid.currentTime - imagusAudio.currentTime <= -0.1) {
imagusAudio.currentTime = imagusVid.currentTime + 0.06;
console.log('time sync corrected');
if (muteTillSync && imagusAudio.readyState > 2) {
imagusAudio.muted = false;
muteTillSync = false;
console.log('unmuted after time correct');
}
} else if (muteTillSync && imagusAudio.readyState > 2) {
imagusAudio.muted = false;
muteTillSync = false;
console.log('unmuted');
}
}
if (eInput || eMouseUp) xPosition = +tooltip.getAttribute('data-x-position');
const xPosPercent = timeTarget ? (xPosition / sliderWidth) * 100 :
Math.round((xPosition / sliderWidth) * 100);
let time = (xPosPercent * v.duration) / 100;
if (eInput || eMeta || eTime || eVolume || eData || !e) {
const valueTrail = timeTarget ? timeProgress : volumeTrail;
const offset = halfSlider < xPosition ? -7 + (xPosition / slider14ths) :
(xPosition - halfSlider) / slider14ths;
slider.value = timeTarget ? xPosPercent : xPosPercent / 100;
valueTrail.style.width = `calc(${xPosPercent}% - ${offset}px)`;
if (eInput && !timeTarget) {
if (start7 || end7) {
vid.volume = start7 ? 0 : 1;
} else {
vid.volume = xPosPercent / 100;
}
}
if (eInput && timeTarget && v.readyState > 0) currentTime.textContent = formatTime(time);
if (eTime) currentTime.textContent = formatTime(v.currentTime);
if (eInput && timeTarget && v.readyState < 1) earlyXposPercent = xPosPercent;
if (eMeta && !tooltip.classList.contains('hidden')) {
xPosition = +tooltip.getAttribute('data-x-position');
time = (xPosition / sliderWidth) * v.duration;
timeText.textContent = formatTime(time);
}
} else if (eMouseUp) {
if (audioSync) {
if (start7 || end7) {
imagusAudio.currentTime = start7 ? 0 : v.duration;
} else {
imagusAudio.currentTime = time;
}
}
if (start7 || end7) {
v.currentTime = start7 ? 0 : v.duration;
} else {
v.currentTime = time;
}
preventMouseMove = true;
setTimeout(() => {
preventMouseMove = false;
}, 10);
} else if (eMouseMove || eMouseDown) {
if (!preventMouseMove || eMouseDown) {
tooltip.dataset.xPosition = xPosition;
tooltip.dataset.targetTime = time;
tooltip.style.left = `${eX}px`;
if (v.readyState > 0 && timeTarget) timeText.textContent = formatTime(time);
if (!timeTarget) tooltip.textContent = `${xPosPercent}%`;
}
tooltip.classList.remove('hidden');
preventMouseMove = false;
}
}
function styleBuffer() {
if (v.readyState > 1 && v.duration > 0) {
const buffer = (v.buffered.end(v.buffered.length - 1) / v.duration) * 100;
timeBuffer.style.width = `${buffer}%`;
}
}
function formatTime(t) {
if (isNaN(t)) {
timeTooltip.classList.add('hidden');
return '-:-';
} else {
let seconds = Math.round(t);
const minutes = Math.floor(seconds / 60);
if (minutes > 0) seconds -= minutes * 60;
if (seconds.toString().length === 1) seconds = `0${seconds}`;
return `${minutes}:${seconds}`;
}
}
function volumeValues() {
const videovolume = localStorage.getItem('videovolume');
const videomuted = localStorage.getItem('videomuted');
if ((!videovolume && !videomuted) ||
(videovolume && videovolume === '1' &&
videomuted && videomuted !== 'true')) {
v.volume = 1;
volumeSlider.value = 1;
volumeTrail.style.width = '100%';
localStorage.setItem('videovolume', v.volume);
localStorage.setItem('videomuted', 'false');
} else if (videomuted && videomuted === 'true') {
v.classList.add('muted');
volumeSlider.value = 0;
volumeTrail.style.width = '0';
v.muted = true;
} else {
v.volume = videovolume;
if (audioSync) imagusAudio.volume = v.volume;
sliderValues();
if (!volumeSlider.clientWidth) {
new MutationObserver((_, observer) => {
const volumeWidthSet = v.parentElement.querySelector('volume input').clientWidth;
if (volumeWidthSet) {
sliderValues();
observer.disconnect();
}
}).observe(v.parentElement, {childList: true, subtree: true, attributes: true});
}
}
}
function hasAudio() {
return v.mozHasAudio ||
Boolean(v.webkitAudioDecodedByteCount) ||
Boolean(v.audioTracks && v.audioTracks.length);
}
function compactControls() {
const width = v.clientWidth;
if (!width) return;
if (width < 892) {
v.classList.add('compact');
if (imagus) v.parentNode.parentNode.classList.add('compact');
} else {
v.classList.remove('compact');
if (imagus) v.parentNode.parentNode.classList.remove('compact');
}
width < 412 ? v.classList.add('compact-2') : v.classList.remove('compact-2');
width < 316 ? v.classList.add('compact-3') : v.classList.remove('compact-3');
width < 246 ? v.classList.add('compact-4') : v.classList.remove('compact-4');
}
function imagusMouseDown(e) {
const vid = $('.imagus-video-wrapper');
if (vid && e.button === 2) {
e.stopImmediatePropagation();
imagusMouseTimeout = setTimeout(() => {
imagusMouseTimeout = 'sticky';
}, settings.imagusStickyDelay);
}
}
function imagusMouseUp(e) {
const vid = $('.imagus-video-wrapper');
if (vid && e.button === 2) {
if (imagusMouseTimeout === 'sticky') {
vid.classList.add('stickied');
setTimeout(() => {
v.removeAttribute('controls');
});
if (volume.classList.contains('disabled')) volumeSlider.value = 0;
document.removeEventListener('mousedown', imagusMouseDown, true);
document.removeEventListener('mouseup', imagusMouseUp, true);
} else {
clearInterval(imagusMouseTimeout);
imagusMouseTimeout = false;
}
}
}
function imagusClick(e) {
const imagusStickied = $('.imagus-video-wrapper.stickied');
if (imagusStickied) {
if (e.target.closest('.imagus-video-wrapper.stickied')) {
e.stopImmediatePropagation();
} else {
imagusStickied.removeAttribute('class');
e.preventDefault();
}
}
}
function imagusKeys(e) {
const vid = $('.imagus-video-wrapper');
if (vid) {
if (e.keyCode === 13 || e.keyCode === 90) {
vid.classList.add('stickied');
setTimeout(() => {
v.removeAttribute('controls');
});
if (volume.classList.contains('disabled')) volumeSlider.value = 0;
document.removeEventListener('keyup', imagusKeys, true);
document.removeEventListener('mousedown', imagusMouseDown, true);
document.removeEventListener('mouseup', imagusMouseUp, true);
}
}
}
function handleKeyDown(e) {
if (e.altKey || e.metaKey) return true; // Do not activate
const func = keyFuncs[e.keyCode];
if (func) {
if ((func.length < 3 && e.shiftKey) ||
(func.length < 4 && e.ctrlKey)) return true; // Do not activate
func(e.target, e.keyCode, e.shiftKey, e.ctrlKey);
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
}
function handleKeyOther(e) {
if (e.altKey || e.metaKey) return true; // Do not prevent default
const func = keyFuncs[e.keyCode];
if (func) {
if ((func.length < 3 && e.shiftKey) ||
(func.length < 4 && e.ctrlKey)) return true; // Do not prevent default
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
}
function docHandleKeyDown(e) {
if (document.body !== document.activeElement ||
e.altKey || e.metaKey) return true; // Do not activate
const func = keyFuncs[e.keyCode];
if (func) {
if ((func.length < 3 && e.shiftKey) ||
(func.length < 4 && e.ctrlKey)) return true; // Do not activate
func(v, e.keyCode, e.shiftKey, e.ctrlKey);
e.preventDefault();
e.stopPropagation();
return false;
}
}
function docHandleKeyOther(e) {
if (document.body !== document.activeElement ||
e.altKey || e.metaKey) return true; // Do not prevent default
const func = keyFuncs[e.keyCode];
if (func) {
if ((func.length < 3 && e.shiftKey) ||
(func.length < 4 && e.ctrlKey)) return true; // Do not prevent default
e.preventDefault();
e.stopPropagation();
return false;
}
}
// circumvent any scripts attempting to hijack video context menus
function preventHijack(e) {
e.stopPropagation();
e.stopImmediatePropagation();
const redirectEvent = e.target.ownerDocument.createEvent('MouseEvents');
redirectEvent.initMouseEvent(e, e.bubbles, e.cancelable);
return e;
}
function enforcePosition() {
setTimeout(() => {
let controlsDisplaced = controls !== v.nextSibling;
const vidDisplaced = videoWrapper !== v.parentNode;
if (vidDisplaced || controlsDisplaced) {
if (vidDisplaced) videoWrapper.appendChild(v);
controlsDisplaced = v !== controls.previousSibling;
if (controlsDisplaced) videoWrapper.insertBefore(controls, v.nextSibling);
const bs =
videoWrapper.querySelectorAll('videowrapper > *:not(video):not(controls)');
for (let i = 0; i < bs.length; ++i) {
bs[i].remove();
}
}
repeat++;
if (repeat < 10) enforcePosition.call(this);
}, 100);
}
}
function ytSaveCurrentTime(v) {
v.addEventListener('loadstart', ytCheckSavedTime);
v.addEventListener('loadeddata', ytCheckSavedTime);
v.ontimeupdate = () => {
if (v.currentTime > 0 && ytTimeChecked) localStorage.setItem(ytID, v.currentTime);
};
v.onended = () => {
if (localStorage.getItem(ytID)) localStorage.removeItem(ytID);
};
}
function ytCheckSavedTime(e) {
ytID = location.href.replace(/.*?\/(watch\?v=|embed\/)(.*?)(\?|&|$).*/, '$2');
const savedTime = localStorage.getItem(ytID);
const timeURL = /(\?|&)(t(ime_continue)?|start)=[1-9]/.test(location.href);
const ytStart = $('.ytp-clip-start:not([style*="left: 0%;"])');
if (e.type === 'loadstart') {
ytTimeChecked = false;
if ((!ytStart || !savedTime) && !timeURL) ytTimeChecked = true;
if (ytStart) ytStart.click();
if (ytTimeChecked && savedTime) e.target.currentTime = savedTime;
e.target.focus({preventScroll: true});
if (self === top) window.scroll({top: 0, behavior: 'smooth'});
} else if (e.type === 'loadeddata' && !ytTimeChecked) {
if (savedTime) e.target.currentTime = savedTime;
ytTimeChecked = true;
}
}
function moveStyle() {
const style = $('#custom-native-player-style');
if (!style) return;
const docEls = $$('html > *');
for (let i = 0; i < docEls.length; i++) {
if (docEls[i].tagName === 'STYLE' &&
docEls[i].classList.contains('stylus') &&
docEls[i].id !== 'custom-native-player-style') {
$('html').insertBefore(style, docEls[i]);
break;
} else if (docEls[i] === docEls[docEls.length - 1]) {
$('html').insertBefore(style, docEls[i].nextSibling);
}
}
}
window.addEventListener('DOMContentLoaded', () => {
const style = $('#custom-native-player-style');
!style ? injectStyle() : moveStyle();
setTimeout(moveStyle, 1000);
document.arrive(
'video[controls], video[style*="visibility: inherit !important"]',
{fireOnAttributesModification: true, existing: true}, v => {
if (!v.parentNode.parentNode) return;
const vP = v.parentNode;
const vPP = v.parentNode.parentNode;
const imagus = !v.hasAttribute('controls') &&
$('html > div[style*="z-index: 2147483647"]') === v.parentNode;
const vidOrParentsIdOrClass =
`${v.id}${v.classList}${vP.id}${vP.classList}${vPP.id}${vPP.classList}`;
const exclude = v.classList.contains('custom-native-player') ||
v.classList.contains('imagus') ||
/(v(ideo)?|me)(-|_)?js|jw|jplay|plyr|kalt|flowp|wisti/i.test(vidOrParentsIdOrClass);
if (imagus || (v.hasAttribute('controls') && !exclude)) {
if (imagus) v.classList.add('imagus');
v.classList.add('custom-native-player');
v.classList.add('custom-native-player-hidden');
v.setAttribute('tabindex', '0');
v.setAttribute('preload', 'auto');
v.removeAttribute('controls');
customPlayer(v);
}
});
});
if (/^https?:\/\/www\.youtube\.com/.test(location.href)) {
document.arrive(
'#player video[src*="youtube.com"]',
{fireOnAttributesModification: true, existing: true}, v => {
ytSaveCurrentTime(v);
});
}
const css = `.imagus-video-wrapper {
height: min-content!important;
position: fixed!important;
left: 0!important;
right: 0!important;
top: 0!important;
bottom: 0!important;
margin: auto!important;
box-shadow: none!important;
background-color: hsl(0, 0%, 0%)!important;
width: calc(100% - 100px)!important;
}
.imagus-video-wrapper.stickied {
box-shadow: 0 0 0 100000px hsla(0, 0%, 0%, .7)!important;
}
html > div[style*="2147483647"] div span {
cursor: auto!important;
}
.imagus-video-wrapper videowrapper {
height: 0!important;
padding-top: 56.25%!important;
}
.imagus-video-wrapper videowrapper video.custom-native-player {
position: absolute!important;
}
@media (min-width: 177.778vh) {
.imagus-video-wrapper {
margin: 18px auto!important;
height: calc(100vh - 18px)!important;
width: calc(((100vh - 18px) * 16) / 9)!important;
}
.imagus-video-wrapper videowrapper {
height: 100%!important;
padding-top: 0!important;
}
.imagus-video-wrapper videowrapper video.custom-native-player {
position: relative!important;
}
}
html > div[style*="2147483647"] > img[style*="display: block"] ~ videowrapper {
display: none!important;
}
html > div[style*="2147483647"] {
background: none!important;
box-shadow: none!important;
border: 0!important;
}
html > div[style*="2147483647"] videowrapper + div {
-webkit-text-fill-color: hsl(0, 0%, 90%)!important;
box-shadow: none!important;
width: 100%!important;
max-width: 100%!important;
box-sizing: border-box!important;
overflow: hidden!important;
text-overflow: ellipsis!important;
}
html > div:not(.stickied) video.custom-native-player + controls,
video[controls]:not(.custom-native-player) {
opacity: 0!important;
pointer-events: none!important;
}
videowrapper {
--wrapper-position: relative;
position: var(--wrapper-position)!important;
height: 100%!important;
display: block!important;
font-size: 0px!important;
top: 0!important;
bottom: 0!important;
left: 0!important;
right: 0!important;
background-color: hsl(0, 0%, 0%)!important;
overflow: hidden!important;
}
video.custom-native-player + controls timetooltip,
video.custom-native-player + controls volumetooltip {
position: absolute!important;
display: none!important;
top: -25px!important;
height: 22px!important;
line-height: 22px!important;
text-align: center!important;
border-radius: 4px!important;
font-size: 12px!important;
background: hsla(0, 0%, 0%, .7)!important;
box-shadow: 0 0 4px hsla(0, 0%, 100%, .5)!important;
color: hsl(0, 0%, 100%)!important;
pointer-events: none!important;
}
video.custom-native-player + controls timetooltip timetext {
color: hsl(0, 0%, 100%)!important;
}
video.custom-native-player + controls timetooltip.preview preview {
height: 113px!important;
width: 200px!important;
display: block!important;
}
video.custom-native-player + controls timetooltip.preview {
height: 138px!important;
width: 200px!important;
top: -142px!important;
margin-left: -100px!important;
}
video.custom-native-player + controls timetooltip {
margin-left: -25px!important;
width: 50px!important;
}
video.custom-native-player + controls volumetooltip {
margin-left: -20px!important;
width: 40px!important;
}
video.custom-native-player.compact + controls timeline timetooltip {
top: -25px!important;
}
video.custom-native-player.compact + controls btn,
video.custom-native-player.compact + controls rate,
video.custom-native-player.compact + controls volume {
height: 24px!important;
line-height: 22px!important;
}
video.custom-native-player.compact + controls volume input {
padding-bottom: 2px!important;
}
video.custom-native-player.compact + controls btn:before {
margin-top: -2px!important;
}
video.custom-native-player.compact + controls volume > volumebar {
top: 6px!important;
}
video.custom-native-player + controls timelinewrapper {
height: 100%!important;
line-height: 20px!important;
}
video.custom-native-player + controls timeline:hover timetooltip:not(.hidden),
video.custom-native-player + controls volume:hover volumetooltip:not(.hidden) {
display: inline!important;
}
video.custom-native-player {
user-select: none!important;
cursor: none!important;
max-height: 100%!important;
height: 100%!important;
width: 100%!important;
margin: 0!important;
padding: 0!important;
top: 0!important;
bottom: 0!important;
left: 0!important;
right: 0!important;
background-color: hsl(0, 0%, 0%)!important;
border-radius: 0!important;
}
video.custom-native-player:not(.contains-source):not([src*="/"]) {
cursor: auto!important;
}
video.custom-native-player:not(.contains-source):not([src*="/"]) + controls {
display: none!important;
}
video.custom-native-player + controls > * {
background: none!important;
outline: none!important;
line-height: 32px!important;
font-family: monospace!important;
}
video.custom-native-player.compact + controls > * {
line-height: 24px!important;
}
video.custom-native-player + controls {
--controls-z-index: 1;
white-space: nowrap!important;
transition: opacity .5s ease 0s!important;
background-color: hsla(0, 0%, 0%, .85)!important;
height: 32px !important;
width: 100%!important;
cursor: default !important;
font-size: 18px !important;
user-select: none!important;
z-index: var(--controls-z-index)!important;
flex: none!important;
position: absolute!important;
display: flex!important;
flex-wrap: wrap!important;
opacity: 0!important;
margin: 0!important;
bottom: 0!important;
left: 0!important;
right: 0!important;
}
video.custom-native-player.custom-native-player-hidden,
video.custom-native-player.custom-native-player-hidden + controls {
opacity: 0!important;
pointer-events: none!important;
}
video.custom-native-player.paused + controls,
video.custom-native-player.active + controls,
video.custom-native-player + controls:hover {
opacity: 1!important;
}
video.custom-native-player + controls timeline {
flex-grow: 1!important;
position: relative!important;
align-items: center!important;
flex-direction: column!important;
height: 100%!important;
}
video.custom-native-player + controls timelinewrapper {
flex: 1 0 480px!important;
position: relative!important;
align-items: center!important;
}
video.custom-native-player.compact + controls timelinewrapper {
order: -1;
flex-basis: 100%!important;
height: 20px!important;
}
video.custom-native-player.compact + controls timeline timebar {
top: 5px!important;
}
video.custom-native-player.compact + controls currenttime,
video.custom-native-player.compact + controls totaltime {
line-height: 20px!important;
}
video.custom-native-player.compact + controls {
height: 44px!important;
}
video.custom-native-player.compact-2 + controls btn.begin,
video.custom-native-player.compact-2 + controls btn.skip-short,
video.custom-native-player.compact-3 + controls rate,
video.custom-native-player.compact-3 + controls btn.rate-increase,
video.custom-native-player.compact-3 + controls btn.rate-decrease,
video.custom-native-player.compact-4 + controls btn.skip-long {
display: none!important;
}
video.custom-native-player + controls > * {
display: inline-flex!important;
}
video.custom-native-player.compact-2 + controls btn.rate-increase,
video.custom-native-player.compact-4 + controls btn.toggle-play {
margin-right: auto!important;
}
video.custom-native-player + controls timeline > timebar > timebuffer,
video.custom-native-player + controls timeline > timebar > timeprogress,
video.custom-native-player + controls volume > volumebar > volumetrail {
position: absolute!important;
flex: none!important;
pointer-events: none!important;
height: 100%!important;
border-radius: 20px!important;
}
video.custom-native-player + controls timeline > timebar,
video.custom-native-player + controls volume > volumebar {
position: absolute!important;
height: 10px!important;
border-radius: 20px!important;
overflow: hidden!important;
background-color: hsla(0, 0%, 16%, .85)!important;
top: 11px!important;
left: 0!important;
right: 0!important;
pointer-events: none!important;
z-index: -1!important;
box-shadow: inset 0 0 0 1px hsla(0, 0%, 40%), inset 0 0 5px hsla(0, 0%, 40%, .85)!important;
}
.audio-only.imagus-video-wrapper {
height: 58px!important;
padding: 0!important;
}
.audio-only.imagus-video-wrapper.compact {
height: 78px!important;
}
.audio-only.imagus-video-wrapper video.custom-native-player + controls {
opacity: 1!important;
}
.audio-only.imagus-video-wrapper video.custom-native-player {
height: 0!important;
opacity: 0!important;
min-height: 0!important;
}
.audio-only.imagus-video-wrapper.stickied {
box-shadow: none!important;
}
.audio-only.imagus-video-wrapper videowrapper {
height: 58px!important;
top: auto!important;
padding:0!important;
}
.audio-only.imagus-video-wrapper.compact {
top: 18px!important;
bottom: auto!important;
}
.audio-only.imagus-video-wrapper.compact videowrapper {
height: 78px!important;
}
video.custom-native-player + controls volume.disabled,
video.custom-native-player + controls btn.disabled {
-webkit-filter: brightness(.4);
filter: brightness(.4);
pointer-events: none!important;
}
video.custom-native-player.disabled,
video.custom-native-player.active.disabled {
cursor: default!important;
}
video.custom-native-player.disabled + controls {
opacity: 1!important;
-webkit-filter: brightness(.3)sepia(1)hue-rotate(320deg)saturate(5);
filter: brightness(.3)sepia(1)hue-rotate(320deg)saturate(5);
}
video.custom-native-player.disabled + controls > * {
pointer-events: none!important;
}
video.custom-native-player + controls volume {
max-width: 70px!important;
flex: 1 0 48px!important;
position: relative!important;
margin: 0 12px!important;
height: 100%!important;
}
video.custom-native-player + controls timeline > timebar > timebuffer {
background-color: hsla(0, 0%, 100%, .2)!important;
border-top-right-radius: 20px!important;
border-bottom-right-radius: 20px!important;
left: 0!important;
}
video.custom-native-player + controls timeline > timebar > timeprogress,
video.custom-native-player + controls volume > volumebar > volumetrail {
background-color: hsla(0, 0%, 100%, .4)!important;
left: 0!important;
}
video.custom-native-player + controls volume.disabled volumetrail {
width: 0!important;
}
video.custom-native-player + controls timeline > input {
height: 100%!important;
width: 100%!important;
}
video.custom-native-player.active {
cursor: pointer!important;
}
video.custom-native-player + controls btn {
border: none !important;
cursor: pointer!important;
background-color: transparent!important;
font-family: "Segoe UI Symbol"!important;
font-size: 0!important;
margin: 0!important;
align-items: center!important;
justify-content: center!important;
height: 32px!important;
padding: 0!important;
flex: 1 1 32px!important;
max-width: 46px!important;
box-sizing: content-box!important;
position: relative!important;
opacity: .86!important;
text-shadow: none!important;
transition: opacity .3s, text-shadow .3s!important;
-webkit-text-fill-color: hsl(0, 0%, 100%)!important;
}
video.custom-native-player + controls btn.toggle-play {
flex: 1 1 46px!important
}
video.custom-native-player + controls btn:hover {
opacity: 1!important;
text-shadow: 0 0 8px hsla(0, 0%, 100%)!important;
}
video.custom-native-player.playback-rate-increased + controls btn.rate-increase,
video.custom-native-player.playback-rate-decreased + controls btn.rate-decrease {
-webkit-text-fill-color: cyan!important;
}
video.custom-native-player + controls rate {
height: 32px!important;
width: 42px!important;
margin: 0!important;
display: unset!important;
text-align: center!important;
font-size: 14px!important;
flex-shrink: 0!important;
font-weight: bold!important;
letter-spacing: .5px!important;
-webkit-text-fill-color: hsl(0, 0%, 100%)!important;
user-select: none!important;
pointer-events: none!important;
opacity: .86!important;
}
video.custom-native-player + controls rate[data-current-rate] {
pointer-events: all!important;
cursor: pointer!important;
}
video.custom-native-player + controls rate[data-current-rate]:hover {
transition: opacity .3s, text-shadow .3s!important;
opacity: 1!important;
text-shadow: 0 0 8px hsla(0, 0%, 100%)!important;
}
video.custom-native-player + controls input[type=range] {
-webkit-appearance: none!important;
background-color: transparent !important;
outline: none!important;
border: 0!important;
border-radius: 6px !important;
margin: 0!important;
top: 0!important;
bottom: 0!important;
left: 0!important;
right: 0!important;
padding: 0!important;
height: 100%!important;
width: 100%!important;
position: relative!important;
}
video.custom-native-player + controls input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none!important;
background-color: hsl(0, 0%, 86%)!important;
border: 0!important;
height: 14px!important;
width: 14px!important;
border-radius: 50%!important;
pointer-events: none!important;
}
video.custom-native-player.muted + controls volume input[type='range']::-webkit-slider-thumb {
background-color: hsl(0, 0%, 50%)!important;
}
video.custom-native-player + controls input[type='range']::-moz-range-thumb {
-moz-appearance: none!important;
background-color: hsl(0, 0%, 86%)!important;
border: 0!important;
height: 14px!important;
width: 14px!important;
border-radius: 50%!important;
pointer-events: none!important;
}
video.custom-native-player.muted + controls volume input[type='range']::-moz-range-thumb {
background-color: hsl(0, 0%, 50%)!important;
}
video.custom-native-player + controls currenttime,
video.custom-native-player + controls totaltime {
font-family: monospace, arial!important;
font-weight: bold!important;
font-size: 14px!important;
letter-spacing: .5px!important;
height: 100%!important;
line-height: 32px!important;
min-width: 58px!important;
display: unset!important;
-webkit-text-fill-color: hsl(0, 0%, 86%)!important;
}
video.custom-native-player + controls btn.rate-decrease,
video.custom-native-player + controls btn.rate-increase {
padding: 0!important;
flex: 1 0 14px!important;
max-width: 24px!important;
}
video.custom-native-player + controls btn.rate-decrease {
margin-left: auto!important;
}
video.custom-native-player + controls currenttime {
padding: 0 12px 0 0!important;
margin-right: 2px!important;
text-align: right!important;
}
video.custom-native-player + controls totaltime {
padding: 0 0 0 12px!important;
margin-left: 2px!important;
text-align: left!important;
}
.direct-video-top-level {
margin: 0!important;
padding: 0!important;
display: flex!important;
align-items: center!important;
justify-content: center!important;
}
.direct-video-top-level video {
height: calc(((100vw - 30px) * 9) / 16)!important;
min-height: calc(((100vw - 30px) * 9) / 16)!important;
max-height: calc(((100vw - 30px) * 9) / 16)!important;
width: calc(100vw - 30px)!important;
min-width: calc(100vw - 30px)!important;
max-width: calc(100vw - 30px)!important;
margin: auto!important;
}
.direct-video-top-level > video.custom-native-player + controls {
position: absolute!important;
left: 0!important;
right: 0!important;
margin: 0 auto !important;
width: calc(100vw - 30px)!important;
bottom: calc((100vh - (((100vw - 30px) * 9) / 16)) / 2)!important;
}
@media (min-width: 177.778vh) {
.direct-video-top-level video {
position: unset!important;
height: calc(100vh - 30px)!important;
min-height: calc(100vh - 30px)!important;
max-height: calc(100vh - 30px)!important;
width: calc(((100vh - 30px) * 16) / 9)!important;
min-width: calc(((100vh - 30px) * 16) / 9)!important;
max-width: calc(((100vh - 30px) * 16) / 9)!important;
margin: 8px auto 0!important;
padding: 0!important;
background-color: hsl(0, 0%, 0%)!important;
}
.direct-video-top-level > video.custom-native-player + controls {
width: calc(((100vh - 30px) * 16) / 9)!important;
min-width: calc(((100vh - 30px) * 16) / 9)!important;
max-width: calc(((100vh - 30px) * 16) / 9)!important;
bottom: 15px!important;
}
}
video::-webkit-media-controls,
.native-fullscreen > *:not(video):not(controls) {
display: none!important;
}
.native-fullscreen video.custom-native-player,
.direct-video-top-level .native-fullscreen video.custom-native-player {
height: 100vh!important;
width: 100vw!important;
max-height: 100vh!important;
max-width: 100vw!important;
min-height: 100vh!important;
min-width: 100vw!important;
margin: 0!important;
}
.native-fullscreen video.custom-native-player + controls {
position: fixed!important;
bottom: 0!important;
left: 0!important;
right: 0!important;
margin: 0!important;
width: 100vw!important;
max-width: 100vw!important;
}
video.custom-native-player + controls btn:before {
font-family: 'customNativePlayer'!important;
font-weight: 400!important;
-webkit-font-smoothing: subpixel-antialiased!important;
-moz-osx-font-smoothing: subpixel-antialiased!important;
font-size: 20px!important;
}
video.custom-native-player + controls btn.skip-short.right:before {
content: '\\e90c'!important;
}
video.custom-native-player + controls btn.skip-short.left:before {
content: '\\e90b'!important;
}
video.custom-native-player + controls btn.skip-long.right:before {
content: '\\e901'!important;
}
video.custom-native-player + controls btn.skip-long.left:before {
content: '\\e902'!important;
}
video.custom-native-player + controls btn.begin:before {
content: '\\e908'!important;
}
video.custom-native-player + controls btn.toggle-play:before {
content: '\\e906'!important;
font-size: 26px!important;
}
video.custom-native-player.playing + controls btn.toggle-play:before {
content: '\\e905'!important;
font-size: 24px!important;
}
video.custom-native-player + controls btn.rate-decrease:before {
content: '\\ea0b'!important;
font-size: 10px!important;
}
video.custom-native-player + controls btn.rate-increase:before {
content: '\\ea0a'!important;
font-size: 10px!important;
}
video.custom-native-player + controls btn.mute:before {
content: '\\e90a'!important;
font-size: 22px!important;
}
video.custom-native-player.muted + controls btn.mute:before {
content: '\\e909'!important;
font-size: 22px!important;
}
video.custom-native-player + controls btn.mute.disabled:before {
content: '\\e909'!important;
}
video.custom-native-player + controls btn.expand:before {
content: '\\e904'!important;
font-size: 24px!important;
}
.native-fullscreen video.custom-native-player + controls btn.expand:before {
content: '\\e903'!important;
font-size: 24px!important;
}
@font-face {
font-family: 'customNativePlayer';
src: url(data:application/x-font-woff;charset=utf-8;base64,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) format('woff'), url('customNativePlayer.ttf') format('truetype'), url('customNativePlayer.svg#customNativePlayer') format('svg');
font-weight: normal;
font-style: normal;
}`;
function injectStyle() {
const style = newEl('style');
style.id = 'custom-native-player-style';
style.type = 'text/css';
style.className = 'stylus'; // Dark Reader won't brute force override stylus
style.textContent = css;
document.documentElement.appendChild(style);
}
injectStyle();