// ==UserScript==
// @name Youtube polymer engine fixes
// @description Some fixes for Youtube polymer engine
// @namespace bo.gd.an[at]rambler.ru
// @version 0.5
// @match https://www.youtube.com/*
// @compatible firefox 56
// @author Bogudan
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// test local storage availability (required for settings saving) and load settings
var settings = {}, ls, styles = [];
function lsTest (st, v) {
st.setItem ('__fix_test__', v);
return st.getItem ('__fix_test__') == v;
};
try {
var _s = window.localStorage;
if (lsTest (_s, 'qwe') && lsTest (_s, 'rty')) { // do 2 times just in case LS stored value once, but does not let change it later
ls = _s;
settings = JSON.parse (ls.getItem ('__fix__settings__')) || {};
}
}
catch (e) { }
// settings
var oldsettings = {
"default_player_640": { conv: function (X) { settings ["default_player"] = X ? 3 : 0; }, def: false },
};
for (var S in oldsettings)
if (S in settings) {
var p = oldsettings [S];
p.conv (settings [S]);
delete settings [S];
}
console.log ('fix settings:', settings);
function getSetting (nm, def) { return nm in settings ? settings [nm] : def; }
var presettings = {
// hide "guide" menu
"hide_guide": {
type: "bool",
def: true,
desc: "Hide \"Guide\" menu when page opens",
act: (X) => {
if (!X) return;
var guide_button = document.getElementById ('guide-button');
if (!guide_button) return;
var tmp = guide_button.getElementsByTagName ('button');
if (!tmp.length) return;
tmp = tmp [0].attributes;
if (tmp && tmp ['aria-pressed'].value == 'true')
guide_button.click ();
}
},
// decrease text sizes
"reduce_font": {
type: "bool",
def: true,
desc: "Reduce font size in video descriptions",
act: (X) => {
if (!X) return;
styles.push ('#video-title.ytd-rich-grid-video-renderer,#text.ytd-channel-name,#metadata-line.ytd-video-meta-block{font-size:14px!important;line-height:1.2em!important}');
// fix: "not interested" placeholder bigger than original element by about 40%
styles.push ('paper-button.style-blue-text{padding:0!important}');
}
},
// fix: home page thumbnails size (1/3 of original image sizes)
"reduce_thumbnail": {
type: "bool",
def: true,
desc: "Reduce thumbnails width to 240px",
act: (X) => {
if (X)
styles.push ('ytd-rich-item-renderer{width:240px!important}');
}
},
"default_player": {
type: "list",
def: 0,
desc: "Set player size in default mode",
opts: ['default', '256x144px', '426x240px', '640x360px', '853x480px', '1280x720px'],
act: (X) => {
if (!X) return;
var w = [0, 256, 427, 640, 854, 1280] [X] + 'px!important';
var h = [0, 144, 240, 360, 480, 720] [X] + 'px!important';
styles.push ('#player-container-outer video.video-stream.html5-main-video{min-height:' + h + ';max-height:' + h + '}');
styles.push ('#player-container-outer video.video-stream.html5-main-video,#player-container-outer div.ytp-chapter-hover-container,#player-container-outer,#player-container-outer div.ytp-chrome-bottom{min-width:' + w + ';max-width:' + w + '}');
styles.push ('#player-container-outer div.ytp-chrome-bottom{left:0!important}');
}
},
"hide_yt_suggested_blocks": {
type: "bool",
def: true,
desc: "Hide YouTube suggestions blocks like \"Recommended playlists\" or \"Latest YouTube posts\"",
act: (X) => {
if (X)
styles.push ('div#contents.ytd-rich-grid-renderer ytd-rich-section-renderer{display:none!important}');
}
},
"unfix_header": {
type: "bool",
def: true,
desc: "Unstick header bar from top of the screen",
act: (X) => {
if (X)
styles.push ('div#masthead-container.ytd-app,ytd-mini-guide-renderer.ytd-app{position:absolute!important}');
}
},
};
// catch "settings" page
if (document.location.pathname == '/fix-settings') {
document.title = "YouTube Polymer Fixes: Settings";
var plane = document.createElement ('div'), e1, e2, e3;
plane.setAttribute ('style', 'position:absolute;left:0;top:0;right:0;bottom:0;background:#eee;padding:3em');
function addLine () {
var q = document.createElement ('div');
for (var i = 0, L = arguments.length; i < L; ++i)
q.appendChild (arguments [i]);
q.setAttribute ('style', 'margin:1em');
plane.appendChild (q);
}
e1 = document.createElement ('b');
e1.appendChild (document.createTextNode ('YouTube Polymer Fixes: Settings'));
addLine (e1);
if (!ls) {
e1 = document.createElement ('span');
e1.style = 'color:red';
e1.appendChild (document.createTextNode ('Cannot edit settings: no access to local storage.'));
e2 = document.createElement ('span');
e2.appendChild (document.createTextNode ('If you using Firefox, allow cookies for this site.'));
addLine (e1, e2);
}
else {
for (var S in presettings) {
var p = presettings [S];
var val = getSetting (S, p.def);
if (p.type == "bool") {
e1 = document.createElement ('input');
e1.setAttribute ('type', 'checkbox');
e1.setAttribute ('style', 'margin-right: 1em;');
if (val)
e1.setAttribute ('checked', '');
e1.name = '__fix__' + S;
e2 = document.createElement ('span');
e2.appendChild (document.createTextNode (p.desc));
addLine (e1, e2);
}
if (p.type == "list") {
e1 = document.createElement ('span');
e1.appendChild (document.createTextNode (p.desc));
e1.setAttribute ('style', 'margin-right: 1em;');
e2 = document.createElement ('select');
for (var i = 0, L = p.opts.length; i < L; ++i) {
e3 = e2.appendChild (document.createElement ('option'));
e3.appendChild (document.createTextNode (p.opts [i]));
if (i == val)
e3.setAttribute ('selected', '');
}
e2.setAttribute ('style', 'padding: 0.2em;border:1px solid #888');
e2.name = '__fix__' + S;
addLine (e1, e2);
}
}
e1 = document.createElement ('input');
e1.setAttribute ('type', 'button');
e1.setAttribute ('style', 'padding:0.4em;border:1px solid #888');
e1.value = 'Save settings and return to YouTube';
e1.addEventListener ('click', function () {
settings = {};
for (var S in presettings) {
var p = presettings [S];
var e = document.getElementsByName ('__fix__' + S);
if (p.type == "bool")
settings [S] = e [0].checked; // checkbox
if (p.type == "list")
settings [S] = e [0].selectedIndex; // drop-down
}
ls.setItem ('__fix__settings__', JSON.stringify (settings));
alert ('Settings saved');
history.back ();
});
e2 = document.createElement ('input');
e2.setAttribute ('type', 'button');
e2.setAttribute ('style', 'padding:0.4em;border:1px solid #888');
e2.value = 'Return to YouTube without saving';
e2.addEventListener ('click', function () {
history.back ();
});
addLine (e1, document.createTextNode (' '), e2);
}
document.body.appendChild (plane);
return;
}
// "settings" button
function createSettingsButton () {
var toolBar = document.getElementsByTagName ('ytd-topbar-menu-button-renderer');
var _1st = toolBar [0];
if (!_1st)
return setTimeout (createSettingsButton, 1000);
toolBar = _1st.parentNode;
var sb = document.createElement ('ytd-topbar-menu-button-renderer');
sb.className = 'style-scope ytd-masthead style-default';
sb.setAttribute ('use-keyboard-focused', '');
sb.setAttribute ('is-icon-button', '');
sb.setAttribute ('has-no-text', '');
toolBar.insertBefore (sb, toolBar.childNodes [0]);
var icb = document.createElement ('yt-icon-button');
icb.id = 'button';
icb.className = 'style-scope ytd-topbar-menu-button-renderer style-default';
var aa = document.createElement ('a');
aa.className = 'yt-simple-endpoint style-scope ytd-topbar-menu-button-renderer';
aa.setAttribute ('tabindex', '-1');
aa.setAttribute ('href', '/fix-settings');
aa.appendChild (icb);
//aa.appendChild (tt);
sb.getElementsByTagName ('div') [0].appendChild (aa); // created by YT scripts
var bb = icb.getElementsByTagName ('button') [0]; // created by YT scripts
bb.setAttribute ('aria-label', 'fixes settings');
var ic = document.createElement ('yt-icon');
ic.className = 'style-scope ytd-topbar-menu-button-renderer';
bb.appendChild (ic);
var gpath = document.createElementNS ('http://www.w3.org/2000/svg', 'path');
gpath.className.baseVal = 'style-scope yt-icon';
gpath.setAttribute ('d', 'M1 20l6-6h2l11-11v-1l2-1 1 1-1 2h-1l-11 11v2l-6 6h-1l-2-2zM13 15l2-2 8 8v1l-1 1h-1zM9 11l2-2-2-2 1.5-3-3-3h-2l3 3-1.5 3-3 1.5-3-3v2l3 3 3-1.5z');
var svgg = document.createElementNS ('http://www.w3.org/2000/svg', 'g');
svgg.className.baseVal = 'style-scope yt-icon';
svgg.appendChild (gpath);
var svg = document.createElementNS ('http://www.w3.org/2000/svg', 'svg');
svg.className.baseVal = 'style-scope yt-icon';
svg.setAttributeNS (null, 'viewBox', '0 0 24 24');
svg.setAttributeNS (null, 'preserveAspectRatio', 'xMidYMid meet');
svg.setAttribute ('focusable', 'false');
svg.setAttribute ('style', 'pointer-events: none; display: block; width: 100%; height: 100%;');
svg.appendChild (svgg);
ic.appendChild (svg); // YT clears *ic
}
createSettingsButton ();
// hide "guide" menu
for (var S in presettings) {
var p = presettings [S];
p.act (getSetting (S, p.def));
}
// styles
if (styles.length > 0) {
var style_element = document.createElement ('style');
style_element.type = 'text/css';
style_element.innerHTML = styles.join ('');
document.body.appendChild(style_element);
}
})();