Advertisement
Guest User

fixded fix - for my friend

a guest
Nov 20th, 2021
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.69 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Youtube polymer engine fixes
  3. // @description Some fixes for Youtube polymer engine
  4. // @namespace bo.gd.an[at]rambler.ru
  5. // @version 2.10.4
  6. // @match https://www.youtube.com/*
  7. // @compatible firefox 56
  8. // @author Bogudan
  9. // @grant GM_info
  10. // @grant GM.info
  11. // @grant GM_getValue
  12. // @grant GM.getValue
  13. // @grant GM_setValue
  14. // @grant GM.setValue
  15. // @noframes
  16. // @run-at document-start
  17. // @license For personal use only
  18. // @require https://greasyfork.org/scripts/427473-object-setdefault/code/object_setDefault.js?version=937466
  19. // ==/UserScript==
  20.  
  21. (function () {
  22. 'use strict';
  23. if (document.location.pathname == '/error') // нам нечего делать на страницах с ошибками
  24. return;
  25. // test local storage availability and load settings from there first
  26. let settings, ls, saver;
  27. try {
  28. function lsTest(st, v) {
  29. st.setItem('__fix_test__', v);
  30. return st.getItem('__fix_test__') == v;
  31. };
  32. const _s = window.localStorage;
  33. if (lsTest(_s, 'qwe') && lsTest(_s, 'rty')) { // do 2 times just in case LS stored value once, but does not let change it later
  34. ls = _s;
  35. ls.removeItem('__fix_test__');
  36. settings = JSON.parse(ls.getItem('__fix__settings__'));
  37. }
  38. }
  39. catch (e) { }
  40. // select storage: GM_*/GM.* or local storage (in case userscript manager does not grant us GMs)
  41. if (typeof (GM_getValue) !== 'undefined' && typeof (GM_setValue) !== 'undefined' && GM_getValue && GM_setValue) {
  42. saver = function () {
  43. GM_setValue('settings', settings);
  44. }
  45. if (!settings)
  46. settings = GM_getValue('settings', {});
  47. else {
  48. saver();
  49. ls.removeItem('__fix__settings__');
  50. }
  51. settings.storage = 'GM_*Value';
  52. }
  53. else if (typeof (GM) !== 'undefined' && GM && GM.getValue && GM.setValue) {
  54. saver = function () {
  55. (async () => await GM.setValue('settings', settings))();
  56. };
  57. if (!settings)
  58. settings = (async () => await GM.getValue('settings', {}))();
  59. else {
  60. saver();
  61. ls.removeItem('__fix__settings__');
  62. }
  63. settings.storage = 'GM.*Value';
  64. }
  65. else if (ls) {
  66. if (!settings)
  67. settings = {};
  68. saver = function () {
  69. ls.setItem('__fix__settings__', JSON.stringify(settings));
  70. };
  71. settings.storage = 'window.localStorage.*Item';
  72. }
  73. else
  74. settings = {};
  75. // delete old settings
  76. if ("default_player_640" in settings) { // удалено в 0.5
  77. settings.default_player = settings.default_player_640 ? 3 : 0;
  78. delete settings.default_player_640;
  79. }
  80. if ("reduce_thumbnail" in settings) { // удалено в 0.6.0
  81. settings.thumbnail_size = settings.reduce_thumbnail ? 2 : 0;
  82. delete settings.reduce_thumbnail;
  83. }
  84. if ("reduce_font" in settings) { // удалено в 2.5.8: размеры текста уменьшились на стороне YT
  85. settings.fix_removed_placeholder = settings.reduce_font;
  86. delete settings.reduce_font;
  87. }
  88. if ("wide_description" in settings) { // удалено в 2.9.1
  89. settings.description_width = settings.wide_description ? 1 : 0;
  90. delete settings.wide_description;
  91. }
  92. // set default values
  93. const gminfo = typeof (GM_info) !== 'undefined' && GM_info || typeof (GM) !== 'undefined' && GM && GM.info;
  94. const fix_version = gminfo && gminfo.script && gminfo.script.version;
  95. if (fix_version) {
  96. settings.version = fix_version;
  97. settings.setDefault("inst_ver", fix_version);
  98. }
  99. settings.setDefault("align_player", 0);
  100. settings.setDefault("default_player", 0);
  101. settings.setDefault("hide_guide", true);
  102. settings.setDefault("hide_yt_suggested_blocks", true);
  103. settings.setDefault("logo_target", "");
  104. settings.setDefault("fix_removed_placeholder", true);
  105. settings.setDefault("theater_player", 0);
  106. settings.setDefault("thumbnail_size", 2);
  107. settings.setDefault("thumbnail_size_m", 720);
  108. settings.setDefault("unfix_header", true);
  109. settings.setDefault("search_thumbnail", 0);
  110. settings.setDefault("clear_search", false);
  111. settings.setDefault("channel_top", 0);
  112. settings.setDefault("try_load_more", false);
  113. settings.setDefault("unbound_video_title", false);
  114. settings.setDefault("video_quality", 0);
  115. settings.setDefault("no_resume_time", false);
  116. settings.setDefault("remove_yt_redirect", false);
  117. settings.setDefault("exact_view_count", false);
  118. settings.setDefault("resume_bar_handling", settings.no_resume_time ? 1 : 0);
  119. settings.setDefault("watched_grayscale", 0);
  120. settings.setDefault("watched_blur", 0);
  121. settings.setDefault("disable_player_click_overlay", false);
  122. settings.setDefault("description_width", 0);
  123. settings.setDefault("simpler_fullscreen", false);
  124. settings.setDefault('clear_link_pp', false);
  125. console.log('fix settings:', settings);
  126. // catch "settings" page
  127. if (document.location.pathname == '/fix-settings') {
  128. document.title = "HACK MENU: Settings";
  129. const back = document.createElement('div');
  130. back.className = 'ytfixback';
  131. const plane = document.createElement('div');
  132. plane.className = 'ytfix';
  133. const style = document.createElement('style');
  134. style.type = 'text/css';
  135. style.innerHTML = `
  136. .ytfix{position:absolute;left:0;top:0;right:0;background:#eee;padding:3em}
  137. .ytfix_line{margin:1em}
  138. .ytfix_line span,.ytfix_line input,.ytfix_line select{margin-right:1em}
  139. .ytfix_field{padding:0.2em;border:1px solid #888}
  140. .ytfix_button{padding:0.4em;border:1px solid #888}
  141. .ytfix_line fieldset {border:1px solid #ccc;padding:0 0.5em}
  142. .ytfix_line legend {padding:0 0.5em}
  143. .ytfix_line img {margin:0 1em}
  144. .ytfix_hide{display:none}
  145. .ytfixback{position:absolute;left:0;top:0;right:0;height:100%;background:#eee}
  146. .ytfix_slide_base {position:relative;margin-right:1em;display:inline-block;height:1em}
  147. .ytfix_slide_bar {position:absolute;left:0;right:0;top:0.3em;bottom:0.3em;background:#ddd;border:1px solid #ccc}
  148. .ytfix_slide_stroke {position:absolute;width:1px;top:0.1em;bottom:0.1em;background:#ccc}
  149. .ytfix_slide_arrow {position:absolute;width:9px;bottom:0;top:0;background:#ddd;border:1px solid #aaa;border-radius:0.5em}
  150. .ytfix_tabs {position:relative}
  151. .ytfix_tabs > div {display:none;border:1px solid #ccc}
  152. .ytfix_tabs > input {display:none}
  153. .ytfix_tabs > label {display:inline-block;background:#ddd;border:1px solid #ccc;padding:0.5em 1em;position:relative;top:1px}
  154. .ytfix_tabs > label ~ label {border-left:none}
  155. .ytfix_tabs > input:checked + label {background-color:#eee;border-bottom:1px solid #eee}
  156. `;
  157. plane.appendChild(style);
  158. function AddLine(plane) {
  159. const q = document.createElement('div');
  160. q.className = 'ytfix_line';
  161. for (let i = 1, L = arguments.length; i < L; ++i)
  162. q.appendChild(arguments[i]);
  163. plane.appendChild(q);
  164. return q;
  165. }
  166. let e1, e2;
  167. e1 = document.createElement('b');
  168. e1.appendChild(document.createTextNode('HACK MENU: Settings'));
  169. AddLine(plane, e1);
  170. if (fix_version) {
  171. e1 = document.createElement('b');
  172. e1.appendChild(document.createTextNode(`Version: ${fix_version}`));
  173. AddLine(plane, e1);
  174. }
  175. if (!saver) {
  176. e1 = document.createElement('span');
  177. e1.style = 'color:red';
  178. e1.appendChild(document.createTextNode('Cannot edit settings: no access to any storage.'));
  179. AddLine(plane, e1);
  180. e1 = document.createElement('span');
  181. e1.appendChild(document.createTextNode('If you are using Firefox, allow cookies for this site.'));
  182. AddLine(plane, e1);
  183. }
  184. else {
  185. const ess = {};
  186. function MakeDesc(desc, extra) {
  187. const e = document.createElement('span');
  188. e.appendChild(document.createTextNode(desc));
  189. if (extra) {
  190. if (extra.style)
  191. e.style = style;
  192. if (extra.note) {
  193. const n = document.createElement('sup');
  194. n.appendChild(document.createTextNode(extra.note));
  195. e.appendChild(n);
  196. }
  197. }
  198. return e;
  199. }
  200. function MakeNote(num, desc, extra) {
  201. const e = document.createElement('span');
  202. if (num) {
  203. const n = document.createElement('sup');
  204. n.appendChild(document.createTextNode(num));
  205. e.appendChild(n);
  206. }
  207. e.appendChild(document.createTextNode(desc));
  208. if (extra && extra.style)
  209. e.style = 'font-size:0.75em;' + extra.style;
  210. else
  211. e.style = 'font-size:0.75em';
  212. return e;
  213. }
  214. function MakeBoolElement(nm) {
  215. const e = document.createElement('input');
  216. e.type = 'checkbox';
  217. e.checked = settings[nm];
  218. ess[nm] = e;
  219. return e;
  220. }
  221. function MakeListElement(nm, opts) {
  222. const e = document.createElement('select');
  223. e.className = 'ytfix_field';
  224. ess[nm] = e;
  225. for (let i = 0, L = opts.length; i < L; ++i) {
  226. const o = document.createElement('option');
  227. o.appendChild(document.createTextNode(opts[i]));
  228. e.appendChild(o);
  229. }
  230. e.selectedIndex = settings[nm];
  231. return e;
  232. }
  233. function MakeTextElement(nm) {
  234. const e = document.createElement('input');
  235. e.className = 'ytfix_field';
  236. e.value = settings[nm];
  237. ess[nm] = e;
  238. return e;
  239. }
  240. function MakeSlider(nm, width, snap, steps) {
  241. let desc = { value: -1, mouse: false };
  242. const e = document.createElement('div');
  243. e.className = 'ytfix_slide_base';
  244. e.style.width = `${width * snap * steps + 1}px`;
  245. const b = document.createElement('div');
  246. b.className = 'ytfix_slide_bar';
  247. e.appendChild(b);
  248. for (let x = width * snap * steps; x >= 0; x -= width * snap) {
  249. const s = document.createElement('div');
  250. s.className = 'ytfix_slide_stroke';
  251. s.style.left = `${x}px`;
  252. e.appendChild(s);
  253. }
  254. const a = document.createElement('div');
  255. a.className = 'ytfix_slide_arrow';
  256. e.appendChild(a);
  257. const i = document.createElement('input');
  258. i.className = 'ytfix_field';
  259. i.type = 'number';
  260. i.style.width = `${(snap * steps).toString().length + 2}em`;
  261. i.min = 0;
  262. i.max = snap * steps;
  263. i.step = 1;
  264. function UpdateValue(newvalue) {
  265. if (newvalue < 0)
  266. newvalue = 0;
  267. else if (newvalue > snap * steps)
  268. newvalue = snap * steps;
  269. if (newvalue == desc.value)
  270. return;
  271. desc.value = newvalue;
  272. a.style.left = `${desc.value * width - 5}px`;
  273. i.value = desc.value;
  274. if (desc.callback)
  275. desc.callback(desc);
  276. }
  277. UpdateValue(settings[nm]);
  278. e.addEventListener('mousedown', function (ev) {
  279. if (ev.buttons != 1)
  280. return;
  281. desc.mouse = ev.target === a;
  282. if (desc.mouse)
  283. return;
  284. let sliderRect = a.getBoundingClientRect();
  285. if (ev.clientX <= sliderRect.left)
  286. UpdateValue(desc.value - snap);
  287. else if (ev.clientX > sliderRect.right)
  288. UpdateValue(desc.value + snap);
  289. });
  290. e.addEventListener('mousemove', function (ev) {
  291. if (ev.buttons != 1 || !desc.mouse)
  292. return;
  293. let mx = ev.clientX - e.getBoundingClientRect().left;
  294. mx += (width * snap) >> 1;
  295. mx -= mx % (width * snap);
  296. UpdateValue(mx / width);
  297. });
  298. i.addEventListener('input', function () {
  299. if (/^\d+$/.test(i.value))
  300. UpdateValue(parseInt(i.value));
  301. });
  302. desc.base = e;
  303. desc.input = i;
  304. ess[nm] = desc;
  305. return desc;
  306. }
  307. function MakeButton(text, click) {
  308. const e = document.createElement('input');
  309. e.type = 'button';
  310. e.className = 'ytfix_button';
  311. e.value = text;
  312. e.addEventListener('click', click);
  313. return e;
  314. }
  315. const tabs_data = [];
  316. function MakeTab(name, text, checked) {
  317. const inp = document.createElement('input');
  318. inp.type = 'radio';
  319. inp.id = name;
  320. inp.name = 'tabs';
  321. if (checked)
  322. inp.setAttribute('checked', '');
  323. const lbl = document.createElement('label');
  324. lbl.setAttribute('for', name);
  325. lbl.appendChild(document.createTextNode(text));
  326. const cont = document.createElement('div');
  327. cont.id = name + '_cont';
  328. style.innerHTML += `.ytfix_tabs > input#${name}:checked ~ div#${name}_cont {display:block}`;
  329. tabs_data.push({ inp: inp, lbl: lbl, cont: cont });
  330. return cont;
  331. }
  332. const tab_gen = MakeTab('tab_gen', 'General', true);
  333. const tab_front = MakeTab('tab_front', 'Front page', false);
  334. const tab_search = MakeTab('tab_search', 'Search', false);
  335. const tab_video = MakeTab('tab_video', 'Video', false);
  336. const tab_channel = MakeTab('tab_channel', 'Channel', false);
  337. const tabs_data_2 = [plane];
  338. tabs_data.forEach((x) => tabs_data_2.push(x.inp, x.lbl));
  339. const tabbf = document.createElement('div');
  340. tabbf.style = 'display:block;width:1px;height:2px;border-width:0 0 0 1px;position:absolute';
  341. tabs_data_2.push(tabbf);
  342. tabs_data.forEach((x) => tabs_data_2.push(x.cont));
  343. const tabs = AddLine.apply(this, tabs_data_2);
  344. tabs.className += ' ytfix_tabs';
  345.  
  346. AddLine(tab_gen, MakeBoolElement("hide_guide"), MakeDesc('Hide "Guide" menu when page opens'));
  347. AddLine(tab_video, MakeBoolElement("fix_removed_placeholder"), MakeDesc('Make size of "Video removed" placeholder about the same as removed video description'));
  348. const tsm = MakeTextElement("thumbnail_size_m");
  349. tsm.className = settings.thumbnail_size == 5 ? 'ytfix_field' : 'ytfix_hide';
  350. const tsi = MakeListElement("thumbnail_size", ['default', '180px', '240px', '360px', '480px', 'manual']);
  351. tsi.addEventListener('change', function () {
  352. ess.thumbnail_size_m.className = ess.thumbnail_size.selectedIndex == 5 ? 'ytfix_field' : 'ytfix_hide';
  353. });
  354. AddLine(tab_front, MakeDesc('Set thumbnails width'), tsi, tsm);
  355. AddLine(tab_search, MakeDesc('Set thumbnails width'), MakeListElement("search_thumbnail", ['default', '240px', '360px']));
  356. AddLine(tab_video, MakeDesc("Set player height in default mode"), MakeListElement("default_player", ['default', '144px', '240px', '360px', '480px', '720px']));
  357. AddLine(tab_video, MakeDesc("Set player height in theater mode"), MakeListElement("theater_player", ['default', '144px', '240px', '360px', '480px', '720px']));
  358. AddLine(tab_front, MakeBoolElement("hide_yt_suggested_blocks"), MakeDesc('Hide suggestions blocks (recommended playlists, latest posts, etc.)'));
  359. AddLine(tab_search, MakeBoolElement("clear_search"), MakeDesc("Hide suggestions blocks (for you, people also watched, etc.)"));
  360. AddLine(tab_gen, MakeBoolElement("unfix_header"), MakeDesc("Unstick header bar from top of the screen"));
  361. AddLine(tab_video, MakeDesc("Align resized player into it's container (normal and theater modes)"), MakeListElement("align_player", ['center', 'left', 'right']));
  362. AddLine(tab_channel, MakeDesc("Channel banner behaviour"), MakeListElement('channel_top', ['default', 'hide banner with scrolling', 'hide banner entirely']));
  363. AddLine(tab_gen, MakeBoolElement('try_load_more'), MakeDesc('Add button to try loading more content on pages with dynamic content load'));
  364. AddLine(tab_gen, MakeBoolElement('unbound_video_title'), MakeDesc('Remove size limit for video titles'));
  365. AddLine(tab_gen, MakeDesc("Change YT logo target to https://www.youtube.com/..."), MakeTextElement("logo_target"));
  366. AddLine(tab_gen, MakeBoolElement("remove_yt_redirect"), MakeDesc('Remove YT tracking from links (/redirect?...)'));
  367. AddLine(tab_gen, MakeBoolElement("no_resume_time"), MakeDesc('Remove resume time from the video links (&t=...)'));
  368. AddLine(tab_gen, MakeDesc('Video resume bar (red)'), MakeListElement("resume_bar_handling", ['depending on resume time (default)', 'full width of thumbnail', 'hide']));
  369. const wwfs = document.createElement('fieldset');
  370. const wwl = wwfs.appendChild(document.createElement('legend'));
  371. wwl.appendChild(document.createTextNode('Watched video thumbnails modification'));
  372. const wwt = wwfs.appendChild(document.createElement('table')).appendChild(document.createElement('tr'));
  373. const wwc1 = wwt.appendChild(document.createElement('td'));
  374. const wwgs = MakeSlider('watched_grayscale', 2, 10, 10);
  375. AddLine(wwc1, MakeDesc('Grayscale, %'), wwgs.base, wwgs.input);
  376. const wwb = MakeSlider('watched_blur', 50, 1, 4);
  377. AddLine(wwc1, MakeDesc('Blur, px'), wwb.base, wwb.input);
  378. AddLine(wwc1, MakeNote(0, 'Options require user to be logged into YT account'));
  379. AddLine(wwc1, MakeNote(0, 'Sample image taken from https://unsplash.com/photos/n6TWNDfyPwk'));
  380. const wwc2 = wwt.appendChild(document.createElement('td'));
  381. wwc2.style.textAlign = 'center';
  382. wwc2.appendChild(document.createTextNode('Example'));
  383. wwc2.appendChild(document.createElement('br'));
  384. wwc2.appendChild(document.createElement('img')).src = 'https://picsum.photos/id/197/267/178';
  385. const wwc3 = wwt.appendChild(document.createElement('td'));
  386. wwc3.style.textAlign = 'center';
  387. wwc3.appendChild(document.createTextNode('Modified example'));
  388. wwc3.appendChild(document.createElement('br'));
  389. const wwc3i = wwc3.appendChild(document.createElement('img'));
  390. wwc3i.src = 'https://picsum.photos/id/197/267/178';
  391. function UpdateFilters() {
  392. wwc3i.style.filter = `grayscale(${wwgs.value}%)blur(${wwb.value}px)`;
  393. }
  394. UpdateFilters();
  395. wwgs.callback = UpdateFilters;
  396. wwb.callback = UpdateFilters;
  397. AddLine(tab_gen, wwfs);
  398. AddLine(tab_video, MakeDesc('Starting video quality'), MakeListElement('video_quality', ['Auto (default)', '2160p (4K)', '1440p (HD)', '1080p (HD)', '720p', '480p', '360p', '240p', '144p']));
  399. AddLine(tab_gen, MakeBoolElement("exact_view_count"), MakeDesc('Show exact view counts in video descriptions'));
  400. AddLine(tab_video, MakeBoolElement("disable_player_click_overlay"), MakeDesc('Remove rewinding overlay'));
  401. AddLine(tab_video, MakeDesc("Video description width (including suggested videos column)"), MakeListElement("description_width", ['default', 'stretch', '1200px', '1280px', '1360px', '1440px', '1520px', '1600px', '1680px', '1760px', '1840px', '1920px']));
  402. AddLine(tab_video, MakeBoolElement("simpler_fullscreen"), MakeDesc("Simplify fullscreen (no video description, comments, etc.)"));
  403. AddLine(tab_gen, MakeBoolElement("clear_link_pp"), MakeDesc('Remove &pp= from links'));
  404. e1 = MakeButton('Save settings and return to YouTube', function () {
  405. settings.hide_guide = ess.hide_guide.checked;
  406. settings.fix_removed_placeholder = ess.fix_removed_placeholder.checked;
  407. settings.thumbnail_size = ess.thumbnail_size.selectedIndex;
  408. if (settings.thumbnail_size == 5) {
  409. const v = ess.thumbnail_size_m.value;
  410. if (!/^\d+$/.test(v)) {
  411. alert('Error: invalid value for thumbnails size');
  412. return;
  413. }
  414. settings.thumbnail_size_m = parseInt(v);
  415. }
  416. settings.search_thumbnail = ess.search_thumbnail.selectedIndex;
  417. settings.default_player = ess.default_player.selectedIndex;
  418. settings.theater_player = ess.theater_player.selectedIndex;
  419. settings.hide_yt_suggested_blocks = ess.hide_yt_suggested_blocks.checked;
  420. settings.unfix_header = ess.unfix_header.checked;
  421. settings.align_player = ess.align_player.selectedIndex;
  422. settings.channel_top = ess.channel_top.selectedIndex;
  423. settings.logo_target = ess.logo_target.value;
  424. settings.clear_search = ess.clear_search.checked;
  425. settings.try_load_more = ess.try_load_more.checked;
  426. settings.unbound_video_title = ess.unbound_video_title.checked;
  427. settings.video_quality = ess.video_quality.selectedIndex;
  428. settings.no_resume_time = ess.no_resume_time.checked;
  429. settings.remove_yt_redirect = ess.remove_yt_redirect.checked;
  430. settings.exact_view_count = ess.exact_view_count.checked;
  431. settings.resume_bar_handling = ess.resume_bar_handling.selectedIndex;
  432. settings.watched_grayscale = ess.watched_grayscale.value;
  433. settings.watched_blur = ess.watched_blur.value;
  434. settings.disable_player_click_overlay = ess.disable_player_click_overlay.checked;
  435. settings.description_width = ess.description_width.selectedIndex;
  436. settings.simpler_fullscreen = ess.simpler_fullscreen.checked;
  437. settings.clear_link_pp = ess.clear_link_pp.checked;
  438. saver();
  439. alert('Settings saved');
  440. history.back();
  441. });
  442. e2 = MakeButton('Return to YouTube without saving', function () {
  443. history.back();
  444. });
  445. AddLine(plane, e1, e2);
  446. e1 = MakeButton('Export settings', function () {
  447. const d = document.createElement('a');
  448. d.style.display = 'none';
  449. d.setAttribute('download', 'ytfix_settings.json');
  450. d.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(settings)));
  451. document.body.appendChild(d);
  452. d.click();
  453. document.body.removeChild(d);
  454. });
  455. e2 = MakeButton('Import settings', function () {
  456. const f = document.createElement('input');
  457. f.type = 'file';
  458. f.style.display = 'none';
  459. f.addEventListener('change', function () {
  460. if (f.files.length != 1)
  461. return;
  462. const rdr = new FileReader();
  463. rdr.addEventListener('load', function () {
  464. try {
  465. settings = JSON.parse(rdr.result);
  466. saver();
  467. alert('Settings imported');
  468. document.location.reload();
  469. }
  470. catch (ex) {
  471. alert('Error parsing settings\n' + ex);
  472. }
  473. });
  474. rdr.addEventListener('error', () => alert('Error loading file\n' + rdr.error));
  475. rdr.readAsText(f.files[0]);
  476. });
  477. document.body.appendChild(f);
  478. f.click();
  479. document.body.removeChild(f);
  480. });
  481. AddLine(plane, e1, e2);
  482. }
  483. let int = setInterval(function () {
  484. if (!document.body)
  485. return;
  486. document.body.appendChild(back);
  487. document.body.appendChild(plane);
  488. clearInterval(int);
  489. }, 1);
  490. console.log('Settings page created');
  491. return;
  492. }
  493. // apply settings
  494. let styles = '';
  495. if (settings.hide_guide) {
  496. let url = undefined;
  497. let act = 2;
  498. setInterval(function () {
  499. if (act == 0 && document.location.toString() != url) // обнаружение смены адреса
  500. act = 1;
  501. if (act == 1) { // wait for sorp page load completion
  502. const Q = document.getElementsByTagName('yt-page-navigation-progress');
  503. if (!Q.length || !Q[0].hasAttribute('hidden'))
  504. return;
  505. act = 2;
  506. }
  507. if (act == 2) { // wait for button and press it if necessary
  508. const guide_button = document.getElementById('guide-button');
  509. if (!guide_button)
  510. return;
  511. let tmp = guide_button.getElementsByTagName('button');
  512. if (!tmp.length)
  513. return;
  514. tmp = tmp[0];
  515. if (!tmp.hasAttribute('aria-pressed'))
  516. return;
  517. if (tmp.attributes['aria-pressed'].value == 'true')
  518. guide_button.click();
  519. else {
  520. url = document.location.toString();
  521. act = 0;
  522. window.dispatchEvent(new Event('resize'));
  523. }
  524. }
  525. }, 1000);
  526. }
  527. if (settings.fix_removed_placeholder)
  528. styles += 'paper-button.style-blue-text,tp-yt-paper-button.style-blue-text{padding:0!important}';
  529. if (settings.thumbnail_size)
  530. styles += `
  531. div#contents.style-scope.ytd-rich-grid-renderer {display:block!important}
  532. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer {display:inline!important}
  533. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer > div {display:inline!important;margin:0!important}
  534. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer > div > ytd-rich-item-renderer {display:inline-block!important;width:${[0, 180, 240, 360, 480, settings.thumbnail_size_m][settings.thumbnail_size]}px!important}
  535. ytd-rich-item-renderer.style-scope.ytd-rich-grid-renderer{contain: none !important;display:inline-block!important;width:${[0, 180, 240, 360, 480, settings.thumbnail_size_m][settings.thumbnail_size]}px!important}
  536. `
  537. if (settings.hide_yt_suggested_blocks)
  538. styles += 'div#contents.ytd-rich-grid-renderer ytd-rich-section-renderer{display:none!important}';
  539. if (settings.unfix_header)
  540. styles += `
  541. div#masthead-container.ytd-app,ytd-mini-guide-renderer.ytd-app,app-drawer#guide{position:fixed!important}
  542. ytd-feed-filter-chip-bar-renderer{position:relative!important}
  543. div#chips-wrapper{position:absolute!important;top:0!important}
  544. `;
  545. if (settings.search_thumbnail) {
  546. const sz = [0, 240, 360][settings.search_thumbnail] + 'px!important';
  547. // min-width defaults to 240px, max-width defaults to 360px
  548. // sizes for: videos, playlists, channels, mixes
  549. 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}}`;
  550. }
  551. if (settings.clear_search)
  552. 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}';
  553. styles += [
  554. '#player-theater-container{margin-left:auto!important;margin-right:auto!important}',
  555. '#player-container-outer{margin-left:0!important}',
  556. '#player-container-outer{margin-right:0!important}#player-theater-container{margin-left:auto!important}'
  557. ][settings.align_player];
  558. const sizes = [0, 144, 240, 360, 480, 720];
  559. const size_norm = sizes[settings.default_player];
  560. if (size_norm)
  561. styles += `
  562. ytd-watch-flexy:not([fullscreen]):not([simple-fullscreen]):not([theater]){--ytd-watch-flexy-min-player-height:${size_norm}px!important;--ytd-watch-flexy-max-player-height:${size_norm}px!important;--ytd-watch-flexy-min-player-width:calc(${size_norm}px*var(--ytd-watch-flexy-width-ratio)/var(--ytd-watch-flexy-height-ratio))!important;--ytd-watch-flexy-max-player-width:var(--ytd-watch-flexy-min-player-width)!important}
  563. ytd-watch-flexy:not([fullscreen]):not([simple-fullscreen]):not([theater]) div#player-container-outer.ytd-watch-flexy{height:var(--ytd-watch-flexy-max-player-height);min-width:calc(${size_norm}px*var(--ytd-watch-flexy-width-ratio)/var(--ytd-watch-flexy-height-ratio))!important}
  564. `;
  565. const size_theater = sizes[settings.theater_player];
  566. if (size_theater)
  567. styles += `
  568. ytd-watch-flexy:not([fullscreen]):not([simple-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}
  569. ytd-watch-flexy:not([fullscreen]):not([simple-fullscreen])[theater] div#movie_player{height:${size_theater}px;width:calc(${size_theater}px*var(--ytd-watch-flexy-width-ratio)/var(--ytd-watch-flexy-height-ratio))}
  570. `;
  571. if (size_norm || size_theater)
  572. setInterval(function () {
  573. const eq = document.getElementsByTagName("ytd-watch-flexy");
  574. if (!eq.length)
  575. return;
  576. const s = eq[0].hasAttribute('theater') ? size_theater : size_norm;
  577. if (!s)
  578. return;
  579. const p = document.getElementById("movie_player");
  580. if (!p)
  581. return;
  582. const ep = p.wrappedJSObject || p;
  583. if (ep.setInternalSize && ep.isFullscreen && ep.getPlayerSize && !ep.isFullscreen() && ep.getPlayerSize().height != s)
  584. ep.setInternalSize();
  585. }, 1000);
  586. if (settings.logo_target) {
  587. let url = settings.logo_target;
  588. if (url[0] != '/')
  589. url = '/' + url;
  590. url = document.location.origin + url;
  591. setInterval(function () {
  592. const l = document.querySelectorAll('a#logo');
  593. for (let i = l.length; --i >= 0;) {
  594. const E = l[i];
  595. const D = (E.wrappedJSObject || E).data;
  596. if (D && D.commandMetadata && E.href != url) {
  597. E.href = url;
  598. D.commandMetadata.webCommandMetadata.url = url;
  599. }
  600. }
  601. }, 1000);
  602. }
  603. if (settings.channel_top)
  604. styles += 'app-header#header.style-scope.ytd-c4-tabbed-header-renderer{transform:none!important;position:absolute;left:0px!important;top:0px;margin-top:0px}';
  605. if (settings.channel_top > 1)
  606. styles += `
  607. div#contentContainer.style-scope.app-header-layout{padding-top:148px!important}
  608. div#contentContainer.style-scope.app-header{height:148px!important}
  609. div.banner-visible-area.style-scope.ytd-c4-tabbed-header-renderer{display:none!important}
  610. `;
  611. if (settings.try_load_more) {
  612. setInterval(function () {
  613. const l = document.querySelectorAll('#show-more-button');
  614. let i = l.length;
  615. if (--i >= 0 && l[i].hasAttribute('hidden')) {
  616. l[i].removeAttribute('hidden');
  617. l[i].innerText = 'TRY LOAD MORE';
  618. }
  619. while (--i >= 0)
  620. l[i].parentNode.removeChild(l[i]);
  621. }, 1000);
  622. styles += '#show-more-button{color:var(--yt-spec-call-to-action);width:100%;text-align:center;border:1px solid;padding:1em;cursor:pointer}';
  623. }
  624. if (settings.unbound_video_title)
  625. styles += '#video-title{max-height:none!important;-webkit-line-clamp:none!important}';
  626. if (settings.video_quality) {
  627. function TryQuality(quality, qq, ep) {
  628. return qq.includes(quality) && (ep.setPlaybackQualityRange(quality, quality) || true);
  629. }
  630. let fail = '';
  631. setInterval(function () {
  632. const p = document.getElementById("movie_player");
  633. if (!p)
  634. return;
  635. const ep = p.wrappedJSObject || p;
  636. if (!ep.getPreferredQuality || !ep.getAvailableQualityLevels || !ep.setPlaybackQualityRange || !ep.getVideoData || ep.getPreferredQuality() != 'auto')
  637. return;
  638. const vid = ep.getVideoData().video_id;
  639. if (fail == vid) // данное видео уже обработано
  640. return;
  641. const qq = ep.getAvailableQualityLevels();
  642. if (!qq || !qq.length)
  643. return;
  644. switch (settings.video_quality) { // intentional no breaks here
  645. case 1: if (TryQuality('hd2160', qq, ep)) return;
  646. case 2: if (TryQuality('hd1440', qq, ep)) return;
  647. case 3: if (TryQuality('hd1080', qq, ep)) return;
  648. case 4: if (TryQuality('hd720', qq, ep)) return;
  649. case 5: if (TryQuality('large', qq, ep)) return;
  650. case 6: if (TryQuality('medium', qq, ep)) return;
  651. case 7: if (TryQuality('small', qq, ep)) return;
  652. case 8: if (TryQuality('tiny', qq, ep)) return;
  653. }
  654. console.log('Unknown video qualities in list: ', qq);
  655. fail = vid;
  656. }, 1000);
  657. }
  658. if (settings.resume_bar_handling)
  659. styles += [
  660. '',
  661. 'div.ytd-thumbnail-overlay-resume-playback-renderer{width:100%!important}',
  662. 'ytd-thumbnail-overlay-resume-playback-renderer{display:none!important}'
  663. ][settings.resume_bar_handling];
  664. let watched_filter = '';
  665. if (settings.watched_grayscale)
  666. watched_filter += `grayscale(${settings.watched_grayscale}%)`;
  667. if (settings.watched_blur)
  668. watched_filter += `blur(${settings.watched_blur}px)`;
  669. if (watched_filter)
  670. styles += `a[href*="/watch?"]:not([href^="/watch?"]).ytd-thumbnail img {filter:${watched_filter}}`;
  671. if (settings.no_resume_time || watched_filter) {
  672. const replace = settings.no_resume_time ? '' : '$1';
  673. function removeTimesClearer(l) {
  674. while (l && l.tagName != 'A')
  675. l = l.parentNode;
  676. if (l)
  677. l.href = l.href.replace(/&t=\d+s?/, replace);
  678. }
  679. setInterval(function () {
  680. document.querySelectorAll('a[href^="/watch?"] div.ytd-thumbnail-overlay-resume-playback-renderer').forEach(removeTimesClearer); // основное применение
  681. document.querySelectorAll('a[href^="/watch?"][href*="&t="]').forEach(removeTimesClearer); // на случай прочих ссылок
  682. }, 1000);
  683. }
  684. if (settings.remove_yt_redirect) {
  685. function removeRedirectClearer(l) {
  686. l.href = decodeURIComponent(l.href.replace(/^.*\?(.*&)q=([^&]+)(&.*)?$/, '$2'));
  687. const w = l.wrappedJSObject || l;
  688. if (w.data && w.data.urlEndpoint)
  689. w.data.urlEndpoint.url = l.href;
  690. }
  691. setInterval(function () {
  692. document.querySelectorAll('a[href^="https://www.youtube.com/redirect?"]').forEach(removeRedirectClearer);
  693. }, 1000);
  694. }
  695. if (settings.exact_view_count) {
  696. function getCounterText(x) { // x is not wrapper
  697. try { return x.__data.data.viewCountText.simpleText; } catch (ex) { }
  698. try { return x.__data.data.content.videoRenderer.viewCountText.simpleText; } catch (ex) { }
  699. }
  700. function replaceCountersText(x) {
  701. x = x.wrappedJSObject || x;
  702. const par = x.parentNode.__ytfix_parent;
  703. if (!par)
  704. return;
  705. const tgt = getCounterText(par);
  706. if (tgt && x.textContent != tgt)
  707. x.textContent = tgt;
  708. }
  709. function replaceCountersCallback(mm) {
  710. for (let i = mm.length; --i >= 0;) {
  711. const m = mm[i];
  712. if (m.type == 'characterData')
  713. replaceCountersText(m.target);
  714. }
  715. }
  716. const m = new MutationObserver(replaceCountersCallback);
  717. const opt = { subtree: true, characterData: true };
  718. function replaceCountersEach(x) {
  719. x.setAttribute('ytfix', '');
  720. const ee = x.querySelectorAll('#metadata-line span');
  721. if (ee.length != 2)
  722. return;
  723. const e = ee[0];
  724. (e.wrappedJSObject || e).__ytfix_parent = x;
  725. replaceCountersText(e.firstChild);
  726. m.observe(e, opt);
  727. }
  728. setInterval(function () {
  729. document.querySelectorAll('ytd-compact-video-renderer:not([ytfix])').forEach(replaceCountersEach);
  730. document.querySelectorAll('ytd-grid-video-renderer:not([ytfix])').forEach(replaceCountersEach);
  731. document.querySelectorAll('ytd-rich-item-renderer:not([ytfix])').forEach(replaceCountersEach);
  732. document.querySelectorAll('ytd-video-renderer:not([ytfix])').forEach(replaceCountersEach);
  733. }, 1000);
  734. }
  735. if (settings.disable_player_click_overlay)
  736. styles += 'div.ytp-doubletap-ui,div.ytp-doubletap-ui-legacy {display:none}';
  737. if (settings.description_width) {
  738. const w = [0, '100vw', '1200px', '1280px', '1360px', '1440px', '1520px', '1600px', '1680px', '1760px', '1840px', '1920px'][settings.description_width];
  739. styles += `
  740. ytd-app:not([mini-guide-visible_]) ytd-page-manager {--ytf-width:calc(${w} - 20px);min-width:100%}
  741. ytd-app[mini-guide-visible_] ytd-page-manager {--ytf-width:calc(${w} - 92px);min-width:calc(100% - 92px)}
  742. ytd-watch-flexy[flexy][fullscreen] {min-width:100%!important}
  743. ytd-watch-flexy[flexy] #columns {--ytd-watch-flexy-min-player-width:calc(var(--ytf-width) - var(--ytd-watch-flexy-sidebar-width) - 3 * var(--ytd-margin-6x));min-width:var(--ytf-width)!important;max-width:var(--ytf-width)!important}
  744. `;
  745. }
  746. if (settings.simpler_fullscreen) {
  747. let keys = undefined;
  748. if (document.exitFullscreen)
  749. keys = document.fullscreenEnabled && { enter: 'requestFullscreen', exit: 'exitFullscreen', check: 'fullscreenElement', event: 'fullscreenchange', type: 'standart' };
  750. else if (document.mozCancelFullScreen)
  751. keys = document.mozFullScreenEnabled && { enter: 'mozRequestFullScreen', exit: 'mozCancelFullScreen', check: 'mozFullScreenElement', event: 'mozfullscreenchange', type: 'mozilla' };
  752. else if (document.webkitExitFullscreen)
  753. keys = document.webkitFullscreenEnabled && { enter: 'webkitRequestFullscreen', exit: 'webkitExitFullscreen', check: 'webkitFullscreenElement', event: 'webkitfullscreenchange', type: 'webkit' };
  754. else if (document.msExitFullscreen)
  755. keys = document.msFullscreenEnabled && { enter: 'msRequestFullscreen', exit: 'msExitFullscreen', check: 'msFullscreenElement', event: 'MSFullscreenChange', type: 'microsoft' };
  756. if (!keys)
  757. console.log('unable to determine fullscreen API prefix or fullscreen API disabled');
  758. else {
  759. console.log('detected fullscreen API type:', keys.type);
  760. styles += 'button.ytp-fullerscreen-edu-button{display:none!important}';
  761. document.addEventListener(keys.event, function () {
  762. const enter = !!document[keys.check];
  763. document.getElementById("movie_player").setFauxFullscreen(enter);
  764. for (const q of document.querySelectorAll('ytd-watch-flexy'))
  765. q[enter ? 'setAttribute' : 'removeAttribute']('simple-fullscreen', '');
  766. });
  767. setInterval(function () {
  768. for (const p of document.querySelectorAll('button.ytp-fullscreen-button:not([ytfix])')) {
  769. const q = document.createElement('button');
  770. q.className = p.className;
  771. p.parentNode.appendChild(q);
  772. q.appendChild(p.querySelector('svg'));
  773. q.setAttribute('title', 'Full screen');
  774. p.style.display = 'none';
  775. p.disabled = true;
  776. p.setAttribute('ytfix', '');
  777. q.setAttribute('ytfix', '');
  778. q.addEventListener('mousedown', function (event) {
  779. event.preventDefault();
  780. });
  781. q.addEventListener('click', function (event) {
  782. if (document[keys.check])
  783. document[keys.exit]();
  784. else {
  785. let w = event.target;
  786. while (w && w.tagName != "YTD-PLAYER")
  787. w = w.parentNode;
  788. if (w)
  789. w[keys.enter]();
  790. }
  791. });
  792. }
  793. }, 1000);
  794. }
  795. }
  796. if (settings.clear_link_pp) {
  797. function clearLink(l) {
  798. l.setAttribute('href', l.getAttribute('href').replace(/&pp=[^&]*/, ''));
  799. }
  800. setInterval(function () {
  801. document.querySelectorAll('a[href*="/watch?"][href*="&pp="]').forEach(clearLink);
  802. }, 1000);
  803. }
  804. if (true)
  805. styles += `
  806. div#contents.style-scope.ytd-rich-grid-renderer {display:block!important}
  807. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer {display:inline!important}
  808. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer > div {display:inline!important;margin:0!important}
  809. ytd-rich-grid-row.style-scope.ytd-rich-grid-renderer > div > ytd-rich-item-renderer {contain: none !important;display:inline-block!important}
  810. `;
  811. // "settings" button
  812. // can't store created button: Polymer overrides it's content on soft reload leaving tags in place
  813. // but can store element that Polymer does not know how to deal with and just drops
  814. let settingsMark = { parentNode: false };
  815. setInterval(function () {
  816. if (settingsMark.parentNode)
  817. return;
  818. let toolBar = document.getElementsByTagName('ytd-topbar-menu-button-renderer');
  819. if (!toolBar.length)
  820. return;
  821. toolBar = toolBar[0];
  822. if (!toolBar)
  823. return;
  824. toolBar = toolBar.parentNode;
  825. const sb = document.createElement('ytd-topbar-menu-button-renderer'); // ytd-notification-topbar-button-renderer
  826. sb.className = 'style-scope ytd-masthead style-default'; // style-scope ytd-masthead notification-button-style-type-default
  827. sb.setAttribute('use-keyboard-focused', '');
  828. sb.setAttribute('is-icon-button', '');
  829. sb.setAttribute('has-no-text', '');
  830. const tbo = toolBar.wrappedJSObject || toolBar;
  831. const sbo = sb.wrappedJSObject || sb;
  832. tbo.insertBefore(sbo, tbo.childNodes[0]);
  833. // div[id=notification-count][class=style-scope ytd-notification-topbar-button-renderer][innerHTML=...]
  834. const mark = document.createElement('fix-settings-mark');
  835. mark.style = 'display:none';
  836. toolBar.insertBefore(mark, sb); // must be added to parent node of buttons in order to Polymer dropped it on soft reload
  837. settingsMark = mark;
  838. const icb = document.createElement('yt-icon-button');
  839. icb.id = 'button';
  840. icb.className = 'style-scope ytd-topbar-menu-button-renderer style-default';
  841. const tt = document.createElement('tp-yt-paper-tooltip');
  842. tt.className = 'style-scope ytd-topbar-menu-button-renderer';
  843. tt.setAttribute('role', 'tooltip');
  844. tt.setAttribute('tabindex', '-1');
  845. tt.style = 'right:auto;bottom:auto';
  846. tt.appendChild(document.createTextNode('HACK MENU ')); // YT wraps content into DIV element
  847. const aa = document.createElement('a');
  848. aa.className = 'yt-simple-endpoint style-scope ytd-topbar-menu-button-renderer';
  849. aa.setAttribute('tabindex', '-1');
  850. aa.href = '/fix-settings';
  851. aa.appendChild(icb);
  852. aa.appendChild(tt);
  853. sbo.getElementsByTagName('div')[0].appendChild(aa.wrappedJSObject || aa); // created by YT scripts
  854. const bb = icb.getElementsByTagName('button')[0]; // created by YT scripts
  855. bb.setAttribute('aria-label', 'fixes settings');
  856. const ic = document.createElement('yt-icon');
  857. ic.className = 'style-scope ytd-topbar-menu-button-renderer';
  858. bb.appendChild(ic);
  859. const gpath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  860. gpath.className.baseVal = 'style-scope yt-icon';
  861. 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');
  862. const svgg = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  863. svgg.className.baseVal = 'style-scope yt-icon';
  864. svgg.appendChild(gpath);
  865. const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  866. svg.className.baseVal = 'style-scope yt-icon';
  867. svg.setAttributeNS(null, 'viewBox', '0 0 24 24');
  868. svg.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid meet');
  869. svg.setAttribute('focusable', 'false');
  870. svg.setAttribute('style', 'pointer-events: none; display: block; width: 100%; height: 100%;');
  871. svg.appendChild(svgg);
  872. ic.appendChild(svg); // YT clears *ic
  873. }, 1000);
  874. // styles
  875. if (styles.length) {
  876. let styles_int = setInterval(function () {
  877. if (!document.head)
  878. return;
  879. clearInterval(styles_int);
  880. if (document.getElementById('ytfixstyle'))
  881. return;
  882. const style_element = document.createElement('style');
  883. style_element.setAttribute('type', 'text/css');
  884. style_element.setAttribute('id', 'ytfixstyle');
  885. style_element.innerHTML = styles;
  886. document.head.appendChild(style_element);
  887. }, 100);
  888. }
  889. console.log('Fixes loaded');
  890. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement