// ==UserScript==
// @name Youtube polymer engine fixes
// @description Some fixes for Youtube polymer engine
// @namespace bo.gd.an[at]rambler.ru
// @version 2.6.0
// @match https://www.youtube.com/*
// @compatible firefox 56
// @author Bogudan
// @grant GM_info
// @grant GM.info
// @grant GM_getValue
// @grant GM.getValue
// @grant GM_setValue
// @grant GM.setValue
// @noframes
// @run-at document-start
// @license CC-BY-NC-ND-4.0
// ==/UserScript==
(function () {
'use strict';
if (document.location.pathname == '/error') // нам нечего делать на страницах с ошибками
return;
// test local storage availability and load settings from there first
let settings, ls, saver;
try {
function lsTest (st, v) {
st.setItem ('__fix_test__', v);
return st.getItem ('__fix_test__') == v;
};
const _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;
ls.removeItem ('__fix_test__');
settings = JSON.parse (ls.getItem ('__fix__settings__'));
}
}
catch (e) { }
// select storage: GM_*/GM.* or local storage (in case userscript manager does not grant us GMs)
if (typeof (GM_getValue) !== 'undefined' && typeof (GM_setValue) !== 'undefined' && GM_getValue && GM_setValue) {
saver = function () {
GM_setValue ('settings', settings);
if (ls)
ls.removeItem ('__fix__settings__');
}
if (!settings)
settings = GM_getValue ('settings', {});
else
saver ();
settings.storage = 'GM_*Value';
}
else if (typeof (GM) !== 'undefined' && GM && GM.getValue && GM.setValue) {
saver = function () {
(async () => await GM.setValue ('settings', settings)) ();
if (ls)
ls.removeItem ('__fix__settings__');
};
if (!settings)
settings = (async () => await GM.getValue ('settings', {})) ();
else
saver ();
settings.storage = 'GM.*Value';
}
else if (ls) {
if (!settings)
settings = {};
saver = function () {
ls.setItem ('__fix__settings__', JSON.stringify (settings));
};
settings.storage = 'window.localStorage.*Item';
}
else
settings = {};
// delete old settings
if ("default_player_640" in settings) { // удалено в 0.5
settings.default_player = settings.default_player_640 ? 3 : 0;
delete settings.default_player_640;
}
if ("reduce_thumbnail" in settings) { // удалено в 0.6.0
settings.thumbnail_size = settings.reduce_thumbnail ? 2 : 0;
delete settings.reduce_thumbnail;
}
if ("reduce_font" in settings) { // удалено в 2.5.8: размеры текста уменьшились на стороне YT
settings.fix_removed_placeholder = settings.reduce_font;
delete settings.reduce_font;
}
// set default values
const gminfo = typeof (GM_info) !== 'undefined' && GM_info || typeof (GM) !== 'undefined' && GM && GM.info;
const fix_version = gminfo && gminfo.script && gminfo.script.version;
if (fix_version) {
settings.version = fix_version;
if (!("inst_ver" in settings))
settings.inst_ver = fix_version;
}
if (!("align_player" in settings))
settings.align_player = 0;
if (!("default_player" in settings))
settings.default_player = 0;
if (!("hide_guide" in settings))
settings.hide_guide = true;
if (!("hide_yt_suggested_blocks" in settings))
settings.hide_yt_suggested_blocks = true;
if (!("logo_target" in settings))
settings.logo_target = "";
if (!("fix_removed_placeholder" in settings))
settings.fix_removed_placeholder = true;
if (!("theater_player" in settings))
settings.theater_player = 0;
if (!("thumbnail_size" in settings))
settings.thumbnail_size = 2;
if (!("thumbnail_size_m" in settings))
settings.thumbnail_size_m = 720;
if (!("unfix_header" in settings))
settings.unfix_header = true;
if (!("search_thumbnail" in settings))
settings.search_thumbnail = 0;
if (!("clear_search" in settings))
settings.clear_search = false;
if (!("channel_top" in settings))
settings.channel_top = 0;
if (!("try_load_more" in settings))
settings.try_load_more = false;
if (!("unbound_video_title" in settings))
settings.unbound_video_title = false;
if (!("video_quality" in settings))
settings.video_quality = 0;
if (!("no_resume_time" in settings))
settings.no_resume_time = false;
if (!("remove_yt_redirect" in settings))
settings.remove_yt_redirect = false;
console.log ('fix settings:', settings);
// catch "settings" page
if (document.location.pathname == '/fix-settings') {
document.title = "YouTube Polymer Fixes: Settings";
const back = document.createElement ('div');
back.className = 'ytfixback';
const plane = document.createElement ('div');
plane.className = 'ytfix';
const style = document.createElement ('style');
style.type = 'text/css';
style.innerHTML = `
.ytfix{position:absolute;left:0;top:0;right:0;background:#eee;padding:3em}
.ytfix_line{margin:1em}
.ytfix_line span,.ytfix_line input,.ytfix_line select{margin-right:1em}
.ytfix_field{padding:0.2em;border:1px solid #888}
.ytfix_button{padding:0.4em;border:1px solid #888}
.ytfix_hide{display:none}
.ytfixback{position:absolute;left:0;top:0;right:0;height:100%;background:#eee}
`;
plane.appendChild (style);
function AddLine () {
const q = document.createElement ('div');
q.className = 'ytfix_line';
for (let i = 0, L = arguments.length; i < L; ++i)
q.appendChild (arguments [i]);
plane.appendChild (q);
}
let e1, e2;
e1 = document.createElement ('b');
e1.appendChild (document.createTextNode ('YouTube Polymer Fixes: Settings'));
AddLine (e1);
if (fix_version) {
e1 = document.createElement ('b');
e1.appendChild (document.createTextNode (`Version: ${fix_version}`));
AddLine (e1);
}
if (!saver) {
e1 = document.createElement ('span');
e1.style = 'color:red';
e1.appendChild (document.createTextNode ('Cannot edit settings: no access to any storage.'));
AddLine (e1);
e1 = document.createElement ('span');
e1.appendChild (document.createTextNode ('If you are using Firefox, allow cookies for this site.'));
AddLine (e1);
}
else {
const ess = {};
function MakeDesc (desc) {
const e = document.createElement ('span');
e.appendChild (document.createTextNode (desc));
return e;
}
function MakeBoolElement (nm) {
const e = document.createElement ('input');
e.type = 'checkbox';
e.checked = settings [nm];
ess [nm] = e;
return e;
}
function MakeListElement (nm, opts) {
const e = document.createElement ('select');
e.className = 'ytfix_field';
ess [nm] = e;
for (let i = 0, L = opts.length; i < L; ++i) {
const o = document.createElement ('option');
o.appendChild (document.createTextNode (opts [i]));
e.appendChild (o);
}
e.selectedIndex = settings [nm];
return e;
}
function MakeTextElement (nm) {
const e = document.createElement ('input');
e.className = 'ytfix_field';
e.value = settings [nm];
ess [nm] = e;
return e;
}
function MakeButton (text, click) {
const e = document.createElement ('input');
e.type = 'button';
e.className = 'ytfix_button';
e.value = text;
e.addEventListener ('click', click);
return e;
}
AddLine (MakeBoolElement ("hide_guide"), MakeDesc ('Hide "Guide" menu when page opens'));
AddLine (MakeBoolElement ("fix_removed_placeholder"), MakeDesc ('Make size of "Video removed" placeholder about the same as removed video description'));
const tsm = MakeTextElement ("thumbnail_size_m");
tsm.className = settings.thumbnail_size == 5 ? 'ytfix_field' : 'ytfix_hide';
const tsi = MakeListElement ("thumbnail_size", ['default', '180px', '240px', '360px', '480px', 'manual']);
tsi.addEventListener ('change', function () {
ess.thumbnail_size_m.className = ess.thumbnail_size.selectedIndex == 5 ? 'ytfix_field' : 'ytfix_hide';
});
AddLine (MakeDesc ('Set thumbnails width for front page'), tsi, tsm);
AddLine (MakeDesc ('Set thumbnails width for search page'), MakeListElement ("search_thumbnail", ['default', '240px', '360px']));
AddLine (MakeDesc ("Set player height in default mode"), MakeListElement ("default_player", ['default', '144px', '240px', '360px', '480px', '720px']));
AddLine (MakeDesc ("Set player height in theater mode"), MakeListElement ("theater_player", ['default', '144px', '240px', '360px', '480px', '720px']));
AddLine (MakeBoolElement ("hide_yt_suggested_blocks"), MakeDesc ('Hide suggestions blocks on main page (recommended playlists, latest posts, etc.)'));
AddLine (MakeBoolElement ("clear_search"), MakeDesc ("Hide suggestions blocks in search (for you, people also watched, etc.)"));
AddLine (MakeBoolElement ("unfix_header"), MakeDesc ("Unstick header bar from top of the screen"));
AddLine (MakeDesc ("Align resized player into it's container (normal and theater modes)"), MakeListElement ("align_player", ['center', 'left', 'right']));
AddLine (MakeDesc ("Modify channels' pages behaviour"), MakeListElement ('channel_top', ['default', 'hide banner with scrolling', 'hide banner on load']));
AddLine (MakeBoolElement ('try_load_more'), MakeDesc ('Add button to try loading more content on pages with dynamic content load'));
AddLine (MakeBoolElement ('unbound_video_title'), MakeDesc ('Remove size limit for video titles'));
AddLine (MakeDesc ("Change YT logo target to https://www.youtube.com/..."), MakeTextElement ("logo_target"));
AddLine (MakeBoolElement ("no_resume_time"), MakeDesc ('Remove resume time from the video links (&t=...)'));
AddLine (MakeBoolElement ("remove_yt_redirect"), MakeDesc ('Remove YT tracking from links (/redirect?...)'));
AddLine (MakeDesc ('Starting video quality'), MakeListElement ('video_quality', ['Auto (default)', '2160p (4K)', '1440p (HD)', '1080p (HD)', '720p', '480p', '360p', '240p', '144p']));
e1 = MakeButton ('Save settings and return to YouTube', function () {
settings.hide_guide = ess.hide_guide.checked;
settings.fix_removed_placeholder = ess.fix_removed_placeholder.checked;
settings.thumbnail_size = ess.thumbnail_size.selectedIndex;
if (settings.thumbnail_size == 5) {
const v = ess.thumbnail_size_m.value;
if (!/^\d+$/.test (v)) {
alert ('Error: invalid value for thumbnails size');
return;
}
settings.thumbnail_size_m = parseInt (v);
}
settings.search_thumbnail = ess.search_thumbnail.selectedIndex;
settings.default_player = ess.default_player.selectedIndex;
settings.theater_player = ess.theater_player.selectedIndex;
settings.hide_yt_suggested_blocks = ess.hide_yt_suggested_blocks.checked;
settings.unfix_header = ess.unfix_header.checked;
settings.align_player = ess.align_player.selectedIndex;
settings.channel_top = ess.channel_top.selectedIndex;
settings.logo_target = ess.logo_target.value;
settings.clear_search = ess.clear_search.checked;
settings.try_load_more = ess.try_load_more.checked;
settings.unbound_video_title = ess.unbound_video_title.checked;
settings.video_quality = ess.video_quality.selectedIndex;
settings.no_resume_time = ess.no_resume_time.checked;
settings.remove_yt_redirect = ess.remove_yt_redirect.checked;
saver ();
alert ('Settings saved');
history.back ();
});
e2 = MakeButton ('Return to YouTube without saving', function () {
history.back ();
});
AddLine (e1, e2);
e1 = MakeButton ('Export settings', function () {
const d = document.createElement ('a');
d.style.display = 'none';
d.setAttribute ('download', 'ytfix_settings.json');
d.setAttribute ('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent (JSON.stringify (settings)));
document.body.appendChild (d);
d.click ();
document.body.removeChild (d);
});
e2 = MakeButton ('Import settings', function () {
const f = document.createElement ('input');
f.type = 'file';
f.style.display = 'none';
f.addEventListener ('change', function () {
if (f.files.length != 1)
return;
const rdr = new FileReader ();
rdr.addEventListener ('load', function () {
try {
settings = JSON.parse (rdr.result);
saver ();
alert ('Settings imported');
document.location.reload ();
}
catch (ex) {
alert ('Error parsing settings\n' + ex);
}
});
rdr.addEventListener ('error', () => alert ('Error loading file\n' + rdr.error));
rdr.readAsText (f.files [0]);
});
document.body.appendChild (f);
f.click ();
document.body.removeChild (f);
});
AddLine (e1, e2);
}
let int = setInterval (function () {
if (!document.body)
return;
document.body.appendChild (back);
document.body.appendChild (plane);
clearInterval (int);
}, 1);
console.log ('Settings page created');
return;
}
// apply settings
let styles = '';
const inject_func = [], inject_ints = [];
if (settings.hide_guide) {
function HideGuideTimer (info) {
if (info.act == 0 && document.location.toString () != info.url) // обнаружение смены адреса
info.act = 1;
if (info.act == 1) { // wait for sorp page load completion
const Q = document.getElementsByTagName ('yt-page-navigation-progress');
if (!Q.length || !Q [0].hasAttribute ('hidden'))
return;
info.act = 2;
}
if (info.act == 2) { // wait for button and press it if necessary
const guide_button = document.getElementById ('guide-button');
if (!guide_button)
return;
let tmp = guide_button.getElementsByTagName ('button');
if (!tmp.length)
return;
tmp = tmp [0];
if (!tmp.hasAttribute ('aria-pressed'))
return;
if (tmp.attributes ['aria-pressed'].value == 'true')
guide_button.click ();
else {
info.url = document.location.toString ();
info.act = 0;
window.dispatchEvent (new Event ('resize'));
}
}
}
inject_func.push (HideGuideTimer);
inject_ints.push ({ call: HideGuideTimer, params: [{ act: 2 }] });
}
if (settings.fix_removed_placeholder)
styles += 'paper-button.style-blue-text,tp-yt-paper-button.style-blue-text{padding:0!important}';
if (settings.thumbnail_size)
styles += 'ytd-rich-item-renderer{width:' + [0, 180, 240, 360, 480, settings.thumbnail_size_m] [settings.thumbnail_size] + 'px!important}';
if (settings.hide_yt_suggested_blocks)
styles += 'div#contents.ytd-rich-grid-renderer ytd-rich-section-renderer{display:none!important}';
if (settings.unfix_header)
styles += `
div#masthead-container.ytd-app,ytd-mini-guide-renderer.ytd-app,app-drawer#guide{position:absolute!important}
ytd-feed-filter-chip-bar-renderer{position:relative!important}
div#chips-wrapper{position:absolute!important;top:0!important}
`;
if (settings.search_thumbnail) {
const sz = [0, 240, 360] [settings.search_thumbnail] + 'px!important';
// min-width defaults to 240px, max-width defaults to 360px
// sizes for: videos, playlists, channels, mixes
styles += `ytd-video-renderer[use-prominent-thumbs] ytd-thumbnail.ytd-video-renderer,ytd-playlist-renderer[use-prominent-thumbs] ytd-playlist-thumbnail.ytd-playlist-renderer,ytd-channel-renderer[use-prominent-thumbs] #avatar-section.ytd-channel-renderer,ytd-radio-renderer[use-prominent-thumbs] ytd-thumbnail.ytd-radio-renderer{min-width:${sz};max-width:${sz}}`;
}
if (settings.clear_search)
styles += 'ytd-two-column-search-results-renderer ytd-shelf-renderer.style-scope.ytd-item-section-renderer,ytd-two-column-search-results-renderer ytd-horizontal-card-list-renderer.style-scope.ytd-item-section-renderer{display:none!important}';
styles += [
'#player-theater-container{margin-left:auto!important;margin-right:auto!important}',
'#player-container-outer{margin-left:0!important}',
'#player-container-outer{margin-right:0!important}#player-theater-container{margin-left:auto!important}',
] [settings.align_player];
const sizes = [0, 144, 240, 360, 480, 720];
const size_norm = sizes [settings.default_player];
if (size_norm)
styles += `
ytd-watch-flexy{--ytd-watch-flexy-min-player-height:${size_norm}px!important;--ytd-watch-flexy-max-player-height:${size_norm}px!important;--ytd-watch-flexy-max-player-width:var(--ytd-watch-flexy-min-player-width)!important}
#primary{min-width:calc(max(var(--ytd-watch-flexy-min-player-height)*16/9,var(--ytd-watch-flexy-min-player-width)))!important;max-width:calc(max(var(--ytd-watch-flexy-min-player-height)*16/9,var(--ytd-watch-flexy-min-player-width)))!important}
`;
const size_theater = sizes [settings.theater_player];
if (size_theater)
styles += `ytd-watch-flexy:not([fullscreen])[theater] #player-theater-container{min-width:calc(${size_theater}px*var(--ytd-watch-flexy-width-ratio)/var(--ytd-watch-flexy-height-ratio))!important;max-width:calc(${size_theater}px*var(--ytd-watch-flexy-width-ratio)/var(--ytd-watch-flexy-height-ratio))!important;min-height:${size_theater}px!important;max-height:${size_theater}px!important;height:${size_theater}px!important}`;
if (size_norm || size_theater) {
function SetPlayerSize (sn, st) {
const eq = document.getElementsByTagName ("ytd-watch-flexy");
if (!eq.length)
return;
const s = eq [0].hasAttribute ('theater') ? st : sn;
if (!s)
return;
const ep = document.getElementById ("movie_player");
if (ep && ep.setInternalSize && ep.isFullscreen && ep.getPlayerSize && !ep.isFullscreen () && ep.getPlayerSize ().height != s)
ep.setInternalSize ();
}
inject_func.push (SetPlayerSize);
inject_ints.push ({ call: SetPlayerSize, params: [size_norm, size_theater] });
}
if (settings.logo_target) {
let url = settings.logo_target;
if (url [0] != '/')
url = '/' + url;
url = document.location.origin + url;
function SetLogoURL (url) {
const l = document.querySelectorAll ('a#logo');
for (let i = l.length; --i >= 0; ) {
const Q = l [i];
const D = Q.data;
if (D && D.commandMetadata && Q.href != url) {
Q.href = url;
D.commandMetadata.webCommandMetadata.url = url;
}
}
}
inject_func.push (SetLogoURL);
inject_ints.push ({ call: SetLogoURL, params: [url] });
}
if (settings.channel_top)
styles += 'app-header#header.style-scope.ytd-c4-tabbed-header-renderer{transform:none!important;position:absolute;left:0px!important;top:0px;margin-top:0px}';
if (settings.channel_top > 1)
styles += `
div#contentContainer.style-scope.app-header-layout{padding-top:148px!important}
div#contentContainer.style-scope.app-header{height:148px!important}
div.banner-visible-area.style-scope.ytd-c4-tabbed-header-renderer{display:none!important}
`;
if (settings.try_load_more) {
function TryLoadMore () {
const l = document.querySelectorAll ('#show-more-button');
let i = l.length;
if (--i >= 0 && l [i].hasAttribute ('hidden')) {
l [i].removeAttribute ('hidden');
l [i].innerText = 'TRY LOAD MORE';
}
while (--i >= 0)
l [i].parentNode.removeChild (l [i]);
}
inject_func.push (TryLoadMore);
inject_ints.push ({ call: TryLoadMore });
styles += '#show-more-button{color:var(--yt-spec-call-to-action);width:100%;text-align:center;border:1px solid;padding:1em;cursor:pointer}';
}
if (settings.unbound_video_title)
styles += '#video-title{max-height:none!important}';
if (settings.video_quality) {
function TryQuality (quality, qq, ep) {
return qq.includes (quality) && (ep.setPlaybackQualityRange (quality, quality) || true);
}
function UpdateVideoQuality (det, st) {
const ep = document.getElementById ("movie_player");
if (!ep || !ep.getPreferredQuality || !ep.getAvailableQualityLevels || !ep.setPlaybackQualityRange || !ep.getVideoData || ep.getPreferredQuality () != 'auto')
return;
const vid = ep.getVideoData ().video_id;
if (st.fail == vid) // данное видео уже обработано
return;
const qq = ep.getAvailableQualityLevels ();
if (!qq || !qq.length)
return;
switch (det) { // intentional no breaks here
case 1: if (TryQuality ('hd2160', qq, ep)) return;
case 2: if (TryQuality ('hd1440', qq, ep)) return;
case 3: if (TryQuality ('hd1080', qq, ep)) return;
case 4: if (TryQuality ('hd720', qq, ep)) return;
case 5: if (TryQuality ('large', qq, ep)) return;
case 6: if (TryQuality ('medium', qq, ep)) return;
case 7: if (TryQuality ('small', qq, ep)) return;
case 8: if (TryQuality ('tiny', qq, ep)) return;
}
console.log ('Unknown video qualities in list: ', qq);
st.fail = vid;
};
inject_func.push (TryQuality);
inject_func.push (UpdateVideoQuality);
inject_ints.push ({ call: UpdateVideoQuality, params: [settings.video_quality, {}] });
}
if (settings.no_resume_time) {
styles += 'div.ytd-thumbnail-overlay-resume-playback-renderer{width:100%!important}';
function removeTimesClearer (l) {
l.href = l.href.replace (/&t=\d+s?/, '');
}
function removeTimes () {
document.querySelectorAll ('a[href^="/watch?"][href*="&t="]').forEach (removeTimesClearer);
}
inject_func.push (removeTimesClearer);
inject_func.push (removeTimes);
inject_ints.push ({ call: removeTimes });
}
if (settings.remove_yt_redirect) {
function removeRedirectClearer (l) {
l.href = decodeURIComponent (l.href.replace (/^.*\?(.*&)q=([^&]+)(&.*)?$/, '$2'));
}
function removeRedirect () {
document.querySelectorAll ('a[href^="https://www.youtube.com/redirect?"]').forEach (removeRedirectClearer);
}
inject_func.push (removeRedirectClearer);
inject_func.push (removeRedirect);
inject_ints.push ({ call: removeRedirect });
}
// "settings" button
// can't store created button: Polymer overrides it's content on soft reload leaving tags in place
// but can store element that Polymer does not know how to deal with and just drops
function createSettingsButton (fix_version, st) {
if (st.mark && st.mark.parentNode)
return;
let toolBar = document.getElementsByTagName ('ytd-topbar-menu-button-renderer');
if (!toolBar.length)
return;
toolBar = toolBar [0];
if (!toolBar)
return;
toolBar = toolBar.parentNode;
const sb = document.createElement ('ytd-topbar-menu-button-renderer'); // ytd-notification-topbar-button-renderer
sb.className = 'style-scope ytd-masthead style-default'; // style-scope ytd-masthead notification-button-style-type-default
sb.setAttribute ('use-keyboard-focused', '');
sb.setAttribute ('is-icon-button', '');
sb.setAttribute ('has-no-text', '');
toolBar.insertBefore (sb, toolBar.childNodes [0]);
// div[id=notification-count][class=style-scope ytd-notification-topbar-button-renderer][innerHTML=...]
const mark = document.createElement ('fix-settings-mark');
mark.style = 'display:none';
toolBar.insertBefore (mark, sb); // must be added to parent node of buttons in order to Polymer dropped it on soft reload
st.mark = mark;
const icb = document.createElement ('yt-icon-button');
icb.id = 'button';
icb.className = 'style-scope ytd-topbar-menu-button-renderer style-default';
const tt = document.createElement ('tp-yt-paper-tooltip');
tt.className = 'style-scope ytd-topbar-menu-button-renderer';
tt.setAttribute ('role', 'tooltip');
tt.setAttribute ('tabindex', '-1');
tt.style = 'right:auto;bottom:auto';
tt.appendChild (document.createTextNode ('YT fixes ' + fix_version)); // YT wraps content into DIV element
const aa = document.createElement ('a');
aa.className = 'yt-simple-endpoint style-scope ytd-topbar-menu-button-renderer';
aa.setAttribute ('tabindex', '-1');
aa.href = '/fix-settings';
aa.appendChild (icb);
aa.appendChild (tt);
sb.getElementsByTagName ('div') [0].appendChild (aa); // created by YT scripts
const bb = icb.getElementsByTagName ('button') [0]; // created by YT scripts
bb.setAttribute ('aria-label', 'fixes settings');
const ic = document.createElement ('yt-icon');
ic.className = 'style-scope ytd-topbar-menu-button-renderer';
bb.appendChild (ic);
const 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-2zM2 20v1l1 1h1l5-5v-2h-2zM13 15l2-2 8 8v1l-1 1h-1zM15 14l-1 1 7 7h1v-1zM9 11l2-2-2-2 1.5-3-3-3h-2l3 3-1.5 3-3 1.5-3-3v2l3 3 3-1.5zM9 10l-2-2 1-1 2 2z');
const svgg = document.createElementNS ('http://www.w3.org/2000/svg', 'g');
svgg.className.baseVal = 'style-scope yt-icon';
svgg.appendChild (gpath);
const 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
}
inject_func.push (createSettingsButton);
inject_ints.push ({ call: createSettingsButton, params: [fix_version, {}] });
// styles
function AddStyles () {
if (styles.length == 0)
return;
if (!document.head)
return setTimeout (AddStyles, 1);
const style_element = document.createElement ('style');
style_element.setAttribute ('type', 'text/css');
style_element.setAttribute ('id', 'ytfixstyle');
style_element.innerHTML = styles;
document.head.appendChild (style_element);
}
AddStyles ();
// injection
function InjectScripts () {
if (inject_ints.length == 0)
return;
if (!document.head)
return setTimeout (InjectScripts, 1);
function InjectInterval () {
for (let i = ints.length; --i >= 0; ) {
const Q = ints [i];
try { Q.call.apply (this, Q.params); }
catch (e) { }
}
}
let ss = '(function () {\n';
for (let i = inject_func.length; --i >= 0; )
ss += `${inject_func [i]}\n`;
ss += 'let ints = [\n';
for (let i = inject_ints.length; --i >= 0; ) {
const Q = inject_ints [i];
ss += `{ call: ${Q.call.name}, params: ${JSON.stringify (Q.params || [])} },\n`;
}
ss += `];\n${InjectInterval}\nsetInterval (InjectInterval, 1000);\nconsole.log ("Fixes injected");\n}) ();`;
const sse = document.createElement ('script');
sse.setAttribute ('id', 'ytfixscript');
sse.appendChild (document.createTextNode (ss));
document.head.appendChild (sse);
}
InjectScripts ();
console.log ('Fixes loaded');
}) ();