// ==UserScript== // @name Add Instagram Video Progressbar // @namespace https://greasyfork.org/en/users/85671-jcunews // @version 1.0.4 // @license GNU AGPLv3 // @author jcunews // @description Add a video playback progressbar at bottom of an Instagram video. This script also disables video looping. Both are configurable. // @match *://www.instagram.com/* // @exclude *://www.instagram.com/stories/* // @grant none // @run-at document-start // ==/UserScript== (function(vael, ie, ee, be, wm) { //===== CONFIGURATION BEGIN ===== var ProgressbarHeight = 3; //in pixels. set to zero to hide var ProgressbarColor = "#fff"; //e.g. "#fff" or "#e0e0e0" or "cyan" var ProgressbarElapsedColor = "#f00"; var disableVideoLoop = true; //===== CONFIGURATION END ===== function findTopContainer(elem, sizeDiff) { var parent = elem while (parent.parentNode && (parent.parentNode.clientWidth < (elem.clientWidth + sizeDiff)) && (parent.parentNode.clientHeight < (elem.clientHeight + sizeDiff))) { parent = parent.parentNode } return parent } function moveMuteUp(containerElem) { findTopContainer(containerElem.querySelector('svg'), 40).style.marginBottom = '20px'; } function addSeek(videoElem, bar) { const containerElem = findTopContainer(videoElem, 20) function act(e) { const fractionX = e.offsetX / containerElem.clientWidth const fractionY = e.offsetY / containerElem.clientHeight if (e.altKey == true || fractionY > 0.97) { e.stopPropagation(); bar.style.width = e.offsetX + "px"; videoElem.currentTime = fractionX * videoElem.duration } } containerElem.addEventListener('click', (e) => act(e)) containerElem.addEventListener('mousedown', (e) => act(e)) containerElem.addEventListener('mousemove', (e) => (e.buttons == 1) && act(e)) moveMuteUp(containerElem) } function addBar(a, b) { if (disableVideoLoop) ie = this.parentNode.parentNode.parentNode.parentNode.lastElementChild; a = "aivp" + (new Date()).getTime(); b = a + "bar"; ee = document.createElement("DIV"); ee.id = a; ee.innerHTML = `
`; wm.set(this, be = ee.lastElementChild); this.parentNode.insertBefore(ee, this); addSeek(this, this.parentNode.querySelector("#"+b)); this.removeEventListener("canplay", addBar); } wm = new WeakMap; vael = HTMLVideoElement.prototype.addEventListener; HTMLVideoElement.prototype.addEventListener = function() { var res; ((ve, tm, be) => { function updBar() { be.style.width = Math.ceil((ve.currentTime / ve.duration) * ee.offsetWidth) + "px"; } function startTimer(ev) { if (!be) be = wm.get(this); if (disableVideoLoop) ve.loop = false; if (!tm) tm = setInterval(updBar, 100); } function stopTimer(ev) { if (ev.type === "ended") { be.style.width = "100%"; if (disableVideoLoop) ie.click(); } clearInterval(tm); tm = 0; } res = vael.apply(ve, arguments); if (!ve.attributes["aivp_done"]) { ve.setAttribute("aivp_done", "1"); vael.call(ve, "canplay", addBar); vael.call(ve, "play", startTimer); vael.call(ve, "playing", startTimer); vael.call(ve, "waiting", stopTimer); vael.call(ve, "pause", stopTimer); vael.call(ve, "ended", stopTimer); } })(this); return res; }; })();