- // ==UserScript==
- // @name HTML5 video settings
- // @name:ru Настройки HTML5 видео
- // @namespace html5-video-settings
- // @author smut
- // @version 2020.09.30.1
- // @icon https://img.icons8.com/color/344/video.png
- // @description Change on load default HTML5 video behavior
- // @description:ru Изменение дефолтных параметров воспроизведения HTML5 видео
- // @grant GM_log
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_listValues
- // @grant GM_registerMenuCommand
- // @grant GM.cookie
- // @grant GM_util
- // @grant GM_util.timeout
- // @grant unsafeWindow
- // @grant window.close
- // @exclude /^https?:\/\/([^.]+\.)*?(youtube\.com|coub\.com|youtu\.be|pikabu\.ru)([:/]|$)/
- // @match *://*/*
- // ==/UserScript==
-
- (function() {
-
- 'use strict';
-
- const win = (unsafeWindow || window);
-
- const
- _Document = Object.getPrototypeOf(HTMLDocument.prototype),
- _Element = Object.getPrototypeOf(HTMLElement.prototype);
- const
- _Node = Object.getPrototypeOf(_Element);
-
- const
- isSafari =
- Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 ||
- (function (p) {
- return p.toString() === "[object SafariRemoteNotification]";
- })(!window.safari || window.safari.pushNotification),
- isFirefox = 'InstallTrigger' in win,
- inIFrame = (win.self !== win.top);
- const
- _bindCall = fun => Function.prototype.call.bind(fun),
- _getAttribute = _bindCall(_Element.getAttribute),
- _setAttribute = _bindCall(_Element.setAttribute),
- _removeAttribute = _bindCall(_Element.removeAttribute),
- _hasOwnProperty = _bindCall(Object.prototype.hasOwnProperty),
- _toString = _bindCall(Function.prototype.toString),
- _document = win.document,
- _de = _document.documentElement,
- _appendChild = _Document.appendChild.bind(_de),
- _removeChild = _Document.removeChild.bind(_de),
- _createElement = _Document.createElement.bind(_document),
- _querySelector = _Document.querySelector.bind(_document),
- _querySelectorAll = _Document.querySelectorAll.bind(_document),
- _attachShadow = ('attachShadow' in _Element) ? _bindCall(_Element.attachShadow) : null,
- _apply = Reflect.apply,
- _construct = Reflect.construct;
-
- let skipLander = true;
- try {
- skipLander = !(isFirefox && 'StopIteration' in win);
- } catch (ignore) {}
-
- const jsf = (function () {
- const opts = {};
- let getValue = (a, b) => b,
- setValue = () => null,
- listValues = () => [];
- try {
- [getValue, setValue, listValues] = [GM_getValue, GM_setValue, GM_listValues];
- } catch (ignore) {}
- // defaults
- opts.Lang = 'eng';
- opts.controls = true;
- opts.loop = false;
- opts.autoplay = false;
- opts.muted = false;
- // load actual values
- for (let name of listValues())
- opts[name] = getValue(name, opts[name]);
- const checkName = name => {
- if (!_hasOwnProperty(opts, name))
- throw new Error('Attempt to access missing option value.');
- return true;
- };
- return new Proxy(opts, {
- get(opts, name) {
- if (name === 'toString')
- return () => JSON.stringify(opts);
- if (checkName(name))
- return opts[name];
- },
- set(opts, name, value) {
- if (checkName(name)) {
- opts[name] = value;
- setValue(name, value);
- }
- return true;
- }
- });
- })();
-
- if (isFirefox && _document.constructor.prototype.toString() === '[object ImageDocumentPrototype]')
- return;
-
- if (!NodeList.prototype[Symbol.iterator])
- NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
- if (!HTMLCollection.prototype[Symbol.iterator])
- HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
-
- if (GM.cookie === undefined)
- GM.cookie = {
- list: () => ({
- then: () => null
- })
- };
-
- const
- batchLand = [],
- batchPrepend = new Set(),
- _APIString = `const win = window, isFirefox = ${isFirefox}, inIFrame = ${inIFrame}, _document = win.document, _de = _document.documentElement,
- _Document = Object.getPrototypeOf(HTMLDocument.prototype), _Element = Object.getPrototypeOf(HTMLElement.prototype), _Node = Object.getPrototypeOf(_Element),
- _appendChild = _Document.appendChild.bind(_de), _removeChild = _Document.removeChild.bind(_de), skipLander = ${skipLander},
- _createElement = _Document.createElement.bind(_document), _querySelector = _Document.querySelector.bind(_document),
- _querySelectorAll = _Document.querySelectorAll.bind(_document), _bindCall = fun => Function.prototype.call.bind(fun),
- _getAttribute = _bindCall(_Element.getAttribute), _setAttribute = _bindCall(_Element.setAttribute),
- _removeAttribute = _bindCall(_Element.removeAttribute), _hasOwnProperty = _bindCall(Object.prototype.hasOwnProperty),
- _toString = _bindCall(Function.prototype.toString), _apply = Reflect.apply, _construct = Reflect.construct;
- const GM = { info: { version: '0.0', scriptHandler: null }, cookie: { list: () => ({ then: () => null }) } };
- const jsf = ${jsf.toString()}`,
- landScript = (f, pre) => {
- const script = _createElement('script');
- script.textContent = `(()=>{${_APIString}${[...pre].join(';')};(${f.join(')();(')})();})();`;
- _appendChild(script);
- _removeChild(script);
- },
- startdelay = 2000,
- clickdelay = 1000,
- playdelay = 200;
- var first_load_mute = false;
- var play_click_iframe = false;
- var play_click_timeout;
-
- let scriptLander = f => f();
- if (!skipLander) {
- scriptLander = (func, ...prepend) => {
- prepend.forEach(x => batchPrepend.add(x));
- batchLand.push(func);
- };
- _document.addEventListener(
- 'DOMContentLoaded', () => void(scriptLander = (f, ...prep) => landScript([f], prep)), false
- );
- }
-
- function play_click_switch(play_switch) {
- play_click_iframe = play_switch;
- }
- function html5_video_set(play_click) {
- for (var e of document.getElementsByTagName('video')){
- if (jsf.controls){
- e.setAttribute('controls', '');
- e.controls = "controls";
- if (play_click){
- if (window.location.hostname === 'www.instagram.com'){
- var instaoverlay = document.querySelector('.PyenC');
- var isntacontrol = document.querySelector('.fXIG0');
- //console.log (instaoverlay);
- if(document.querySelector('.PyenC')){
- instaoverlay.parentNode.removeChild(instaoverlay);
- }
- if(document.querySelector('.fXIG0')){
- isntacontrol.parentNode.removeChild(isntacontrol);
- }
- }
- }
- }else{
- e.removeAttribute('controls');
- e.controls = "";
- }
- if (jsf.loop){
- e.setAttribute('loop', '');
- e.loop = "loop";
- }else{
- e.removeAttribute('loop');
- e.loop = "";
- }
- if (jsf.muted && !play_click){
- e.setAttribute('muted', '');
- e.muted = "muted";
- first_load_mute = true;
- }else{
- e.removeAttribute('muted');
- }
- if (jsf.autoplay && !play_click){
- //console.log("autoplay");
- e.setAttribute('autoplay', '');
- e.autoplay = "autoplay";
- e.play();
- }else if (!play_click){
- e.removeAttribute('autoplay');
- e.autoplay = "";
- e.pause();
- //console.log("pause");
- }
- };
- }
-
- const createStyle = (function createStyleModule() {
- function createStyleElement(rules, opts) {
- const style = _createElement('style');
- Object.assign(style, opts.props);
- opts.root.appendChild(style);
-
- if (style.sheet) // style.sheet is only available when style attached to DOM
- rules.forEach(style.sheet.insertRule.bind(style.sheet));
- else
- style.textContent = rules.join('\n');
-
- if (opts.protect) {
- Object.defineProperty(style, 'sheet', {
- value: null,
- enumerable: true
- });
- Object.defineProperty(style, 'disabled', { //pretend to be disabled
- enumerable: true,
- set() {},
- get() {
- return true;
- }
- });
- (new MutationObserver(
- () => opts.root.removeChild(style)
- )).observe(style, {
- childList: true
- });
- }
-
- return style;
- }
-
- // functions to parse object-based rulesets
- function parseRule(rec) {
- /* jshint validthis: true */
- return this.concat(rec[0], ' {\n', Object.entries(rec[1]).map(parseProperty, this + '\t').join('\n'), '\n', this, '}');
- }
-
- function parseProperty(rec) {
- /* jshint validthis: true */
- return rec[1] instanceof Object ? parseRule.call(this, rec) : `${this}${rec[0].replace(/_/g, '-')}: ${rec[1]};`;
- }
-
- // main
- const createStyle = (rules, opts) => {
- // parse options
- opts = Object.assign({
- protect: true,
- root: _de,
- type: 'text/css'
- }, opts);
- // move style properties into separate property
- // { a, b, ...rest } construction is not available in Fx 52
- opts.props = Object.assign({}, opts);
- delete opts.props.protect;
- delete opts.props.root;
- // store binded methods instead of element
- opts.root = {
- appendChild: opts.root.appendChild.bind(opts.root),
- removeChild: opts.root.removeChild.bind(opts.root)
- };
-
- // convert rules set into an array if it isn't one already
- rules = Array.isArray(rules) ? rules : rules instanceof Object ? Object.entries(rules).map(parseRule, '') : [rules];
-
- // could be reassigned when protection triggered
- let style = createStyleElement(rules, opts);
-
- if (!opts.protect)
- return style;
-
- const replaceStyle = () => new Promise(
- resolve => setTimeout(re => re(createStyleElement(rules, opts)), 0, resolve)
- ).then(st => (style = st)); // replace poiner to style object with a new style object
-
- (new MutationObserver(ms => {
- for (let m of ms)
- for (let node of m.removedNodes)
- if (node === style) replaceStyle();
- })).observe(_de, {
- childList: true
- });
-
-
- return style;
- };
- createStyle.toString = () => `const createStyle = (${createStyleModule.toString()})();`;
- return createStyle;
- })();
-
- const lines = {
- linked: [],
- MenuOptions: {
- eng: 'Options',
- rus: 'Настройки'
- },
- langs: {
- eng: 'English',
- rus: 'Русский'
- },
- HeaderName: {
- eng: 'HTML5 video settings',
- rus: 'Настройки HTML5 видео'
- },
- HeaderTools: {
- eng: 'Tools',
- rus: 'Инструменты'
- },
- HeaderOptions: {
- eng: 'Options',
- rus: 'Настройки'
- },
- controlsLabel: {
- eng: 'Show controls',
- rus: 'Отображать элементы управления'
- },
- loopLabel: {
- eng: 'Loop video',
- rus: 'Повтор видео'
- },
- autoplayLabel: {
- eng: 'Autoplay video',
- rus: 'Автоматическое воспроизведение видео'
- },
- autoplayTip: {
- eng: 'Autoplay may not working if "Mute sound" not enabled',
- rus: 'Автовоспроизведение может не работать, если не установлен режим \"отключить звук\"'
- },
- mutedLabel: {
- eng: 'Mute sound',
- rus: 'Отключить звук'
- },
- reg(el, name) {
- this[name].link = el;
- this.linked.push(name);
- },
- setLang(lang = 'eng') {
- for (let name of this.linked) {
- const el = this[name].link;
- const label = this[name][lang];
- el.textContent = label;
- }
- this.langs.link.value = lang;
- jsf.Lang = lang;
- }
- };
-
- const _createTextNode = _Document.createTextNode.bind(_document);
- const createOptionsWindow = () => {
- const root = _createElement('div'),
- shadow = _attachShadow ? _attachShadow(root, {
- mode: 'closed'
- }) : root,
- overlay = _createElement('div'),
- inner = _createElement('div');
-
- overlay.id = 'overlay';
- overlay.appendChild(inner);
- shadow.appendChild(overlay);
-
- inner.id = 'inner';
- inner.br = function appendBreakLine() {
- return this.appendChild(_createElement('br'));
- };
-
- createStyle({
- 'h2': {
- margin_top: 0,
- white_space: 'nowrap'
- },
- 'h2, h3': {
- margin_block_end: '0.5em'
- },
- 'h4': {
- margin_block_start: '0em',
- margin_block_end: '0.5em',
- margin_left: '0.4em',
- font_family: 'Helvetica, Arial, sans-serif',
- font_size: '8pt',
- font_style: 'italic',
- font_weight: 'normal'
- },
- 'div, button, select, input': {
- font_family: 'Helvetica, Arial, sans-serif',
- font_size: '12pt'
- },
- 'select': {
- border: '1px solid darkgrey',
- border_radius: '0px 0px 5px 5px',
- border_top: '0px'
- },
- '#overlay': {
- position: 'fixed',
- top: 0,
- left: 0,
- bottom: 0,
- right: 0,
- background: 'rgba(0,0,0,0.65)',
- z_index: 2147483647 // Highest z-index: Math.pow(2, 31) - 1
- },
- '#inner': {
- background: 'whitesmoke',
- color: 'black',
- padding: '1.5em 1em 1.5em 1em',
- max_width: '150ch',
- position: 'absolute',
- top: '50%',
- left: '50%',
- transform: 'translate(-50%, -50%)',
- border: '1px solid darkgrey',
- border_radius: '5px'
- },
- '#closeOptionsButton': {
- float: 'right',
- transform: 'translate(1em, -1.5em)',
- border: 0,
- border_radius: 0,
- background: 'none',
- box_shadow: 'none'
- },
- '#selectLang': {
- float: 'right',
- transform: 'translate(0, -1.5em)'
- },
- '.optionsLabel': {
- padding_left: '1.5em',
- text_indent: '-1em',
- display: 'block'
- },
- '.optionsCheckbox': {
- left: '-0.25em',
- width: '1em',
- height: '1em',
- padding: 0,
- margin: 0,
- position: 'relative',
- vertical_align: 'middle'
- },
- '@media (prefers-color-scheme: dark)': {
- '#inner': {
- background_color: '#292a2d',
- color: 'white',
- border: '1px solid #1a1b1e'
- },
- 'input': {
- filter: 'invert(100%)'
- },
- 'select': {
- background_color: '#303030',
- color: '#f0f0f0',
- border: '1px solid #1a1b1e',
- border_radius: '0px 0px 5px 5px',
- border_top: '0px'
- },
- '#overlay': {
- background: 'rgba(0,0,0,.85)',
- }
- }
- }, {
- root: shadow,
- protect: false
- });
-
- // components
- function createCheckbox(name) {
- const checkbox = _createElement('input'),
- label = _createElement('label');
- checkbox.type = 'checkbox';
- checkbox.classList.add('optionsCheckbox');
- checkbox.checked = jsf[name];
- checkbox.id = name+'_checkbox';
- checkbox.onclick = e => {
- jsf[name] = e.target.checked;
- return true;
- };
- label.classList.add('optionsLabel');
- label.appendChild(checkbox);
- const text = _createTextNode('');
- label.appendChild(text);
- Object.defineProperty(label, 'textContent', {
- set(title) {
- text.textContent = title;
- }
- });
- return label;
- }
-
- // language & close
- const closeBtn = _createElement('button');
- closeBtn.onclick = () => _removeChild(root);
- closeBtn.textContent = '\u2715';
- closeBtn.id = 'closeOptionsButton';
- inner.appendChild(closeBtn);
-
- overlay.addEventListener('click', e => {
- if (e.target === overlay) {
- _removeChild(root);
- e.preventDefault();
- }
- e.stopPropagation();
- }, false);
-
- const selectLang = _createElement('select');
- for (let name in lines.langs) {
- const langOption = _createElement('option');
- langOption.value = name;
- langOption.innerText = lines.langs[name];
- selectLang.appendChild(langOption);
- }
- selectLang.id = 'selectLang';
- lines.langs.link = selectLang;
- inner.appendChild(selectLang);
-
- selectLang.onchange = e => {
- const lang = e.target.value;
- lines.setLang(lang);
- };
-
- // fill options form
-
- lines.reg(inner.appendChild(_createElement('h2')), 'HeaderName');
-
- lines.reg(inner.appendChild(_createElement('h3')), 'HeaderOptions');
-
- lines.reg(inner.appendChild(createCheckbox('controls')), 'controlsLabel');
- lines.reg(inner.appendChild(createCheckbox('loop')), 'loopLabel');
- lines.reg(inner.appendChild(createCheckbox('autoplay')), 'autoplayLabel');
-
- lines.reg(inner.appendChild(_createElement('h4')), 'autoplayTip');
-
- lines.reg(inner.appendChild(createCheckbox('muted')), 'mutedLabel');
-
- lines.setLang(jsf.Lang);
-
- return root;
- };
-
- let optionsWindow;
- GM_registerMenuCommand(lines.MenuOptions[jsf.Lang], () => _appendChild(optionsWindow = optionsWindow || createOptionsWindow()));
-
- if( document.readyState !== 'loading' ) {
- setTimeout (function () {html5_video_set;}, startdelay);
- } else {
- document.addEventListener('DOMContentLoaded', function () {
- setTimeout (function () {html5_video_set;}, startdelay);
- });
- }
- function video_click(){
- play_click_iframe = true;
- //console.log("play_click_iframe = " + play_click_iframe);
- if(play_click_iframe) {
- clearTimeout(play_click_timeout);
- play_click_timeout = setTimeout(function () {play_click_switch(false);}, clickdelay);
- //setTimeout(function () {console.log("play_click_iframe = " + play_click_iframe);}, clickdelay+100);
- }
- //console.log("clicked");
-
- };
- document.addEventListener('play', function(e){
-
- document.addEventListener('click', video_click, true);
- setTimeout (function () {html5_video_set(play_click_iframe);}, playdelay);
- //console.log("play");
- }, true);
-
- })();