- // ==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();