Advertisement
bruhmoment

Iridium for YouTube (works with Tampermonkey and RAW Paste)

Mar 17th, 2019
484
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 245.02 KB | None | 0 0
  1. // ==UserScript==
  2. // @version 0.2.5
  3. // @name Iridium
  4. // @namespace https://github.com/ParticleCore
  5. // @description YouTube with more freedom
  6. // @compatible firefox
  7. // @compatible chrome
  8. // @icon https://raw.githubusercontent.com/ParticleCore/Iridium/gh-pages/images/i-icon.png
  9. // @match *://www.youtube.com/*
  10. // @run-at document-start
  11. // @homepageURL https://github.com/ParticleCore/Iridium
  12. // @supportURL https://github.com/ParticleCore/Iridium/wiki
  13. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UMVQJJFG4BFHW&lc=US
  14. // @grant GM.getValue
  15. // @grant GM.setValue
  16. // @grant GM_getValue
  17. // @grant GM_setValue
  18. // @noframes
  19. // ==/UserScript==
  20. (function () {
  21. "use strict";
  22.  
  23. var iridium = {
  24.  
  25. inject: function (is_user_script) {
  26.  
  27. var i18n;
  28. var modules;
  29. var iridium_api;
  30. var user_settings;
  31. var default_language;
  32. var send_settings_to_page;
  33. var receive_settings_from_page;
  34.  
  35. default_language = {
  36. language: "English (US)",
  37. section_list: {
  38. donate: "donate",
  39. general: "general",
  40. video: "video",
  41. settings: "settings"
  42. },
  43. section_titles: {
  44. donate: "Support Iridium",
  45. general: "General settings",
  46. video: "Video settings",
  47. settings: "Iridium settings"
  48. },
  49. sub_section_titles: {
  50. channel: "Channel",
  51. blacklist: "Blacklist",
  52. general: "General",
  53. language: "Language",
  54. layout: "Layout",
  55. paypal: "Paypal",
  56. patreon: "Patreon",
  57. playlist: "Playlist",
  58. player: "Player",
  59. settings: "Settings",
  60. thumbnails: "Thumbnails"
  61. },
  62. iridium_api: {
  63. settings_button: "Iridium",
  64. feature_link: "Find out what this does"
  65. },
  66. welcome_box: {
  67. thank_you: "Thank you for installing Iridium!",
  68. settings_instruction: "You can open your settings by clicking the triangle located on the top right corner of this page.",
  69. features_instruction: "For a complete list of features visit the following link:",
  70. features_link: "Feature list",
  71. donate_instruction: "If you wish to help the development of this extension you can use the following options:",
  72. paypal_one_time: "One time donation",
  73. paypal_any_amount: "Any amount",
  74. paypal_monthly: "Monthly donation",
  75. patreon_support: "Support with Patreon",
  76. button_close: "close"
  77. }
  78. };
  79.  
  80. modules = [
  81. {
  82. options: {
  83. default_logo_page: {
  84. id: "default_logo_page",
  85. section: "general",
  86. sub_section: "general",
  87. type: "dropdown",
  88. value: "home",
  89. i18n: {
  90. label: "Default YouTube logo page:",
  91. options: [
  92. "Home",
  93. "Trending",
  94. "Subscriptions"
  95. ]
  96. },
  97. options: [
  98. "home",
  99. "trending",
  100. "subscriptions"
  101. ]
  102. },
  103. default_channel_tab: {
  104. id: "default_channel_tab",
  105. section: "general",
  106. sub_section: "general",
  107. type: "dropdown",
  108. value: "home",
  109. i18n: {
  110. label: "Default channel tab:",
  111. options: [
  112. "Home",
  113. "Videos",
  114. "Playlists",
  115. "Channels",
  116. "Discussion",
  117. "About"
  118. ]
  119. },
  120. options: [
  121. "home",
  122. "videos",
  123. "playlists",
  124. "channels",
  125. "discussion",
  126. "about"
  127. ]
  128. }
  129. },
  130. setDestination: function (event) {
  131.  
  132. var url;
  133. var data;
  134. var parent;
  135. var target;
  136.  
  137. target = event.target;
  138.  
  139. if (!(data = target.data)) {
  140.  
  141. parent = target.parentNode;
  142.  
  143. while (parent) {
  144.  
  145. if (parent.data) {
  146. target = parent;
  147. data = target.data;
  148. break;
  149. }
  150.  
  151. parent = parent.parentNode;
  152.  
  153. }
  154.  
  155. }
  156.  
  157. if (data && (url = iridium_api.getSingleObjectByKey(data, ["webCommandMetadata"])) && (url = url.url)) {
  158.  
  159. if (user_settings.default_channel_tab !== "home" && url.match(/^\/(?:channel|user)\/(?:[^\/])+$/)) {
  160. if (data.commandMetadata && data.commandMetadata.webCommandMetadata) {
  161.  
  162. data.commandMetadata.webCommandMetadata.url += "/" + user_settings.default_channel_tab;
  163.  
  164. if (target.href) {
  165. target.href = data.commandMetadata.webCommandMetadata.url;
  166. }
  167.  
  168. }
  169. }
  170.  
  171. if (user_settings.default_logo_page !== "home" && url === "/" && target.tagName === "A" && target.id === "logo") {
  172.  
  173. if (data.browseEndpoint) {
  174. data.browseEndpoint.browseId = "FE" + user_settings.default_logo_page;
  175. }
  176.  
  177. if (data.commandMetadata && data.commandMetadata.webCommandMetadata) {
  178.  
  179. data.commandMetadata.webCommandMetadata.url += "feed/" + user_settings.default_logo_page;
  180. target.href = data.commandMetadata.webCommandMetadata.url;
  181.  
  182. }
  183.  
  184. }
  185.  
  186. }
  187.  
  188. },
  189. ini: function () {
  190.  
  191. if (iridium_api.initializeOption.call(this)) {
  192. return;
  193. }
  194.  
  195. window.addEventListener("mouseup", this.setDestination.bind(this), true);
  196. window.addEventListener("mousedown", this.setDestination.bind(this), true);
  197.  
  198. }
  199. },
  200. {
  201. options: {
  202. square_avatars: {
  203. id: "square_avatars",
  204. section: "general",
  205. sub_section: "layout",
  206. type: "checkbox",
  207. value: true,
  208. i18n: {
  209. label: "Make user images squared"
  210. }
  211. }
  212. },
  213. ini: function () {
  214.  
  215. if (iridium_api.initializeOption.call(this)) {
  216. return;
  217. }
  218.  
  219. if (user_settings.square_avatars) {
  220. document.documentElement.classList.add("iri-square-avatars");
  221. } else {
  222. document.documentElement.classList.remove("iri-square-avatars");
  223. }
  224.  
  225. }
  226. },
  227. {
  228. options: {
  229. improved_logo: {
  230. id: "improved_logo",
  231. section: "general",
  232. sub_section: "layout",
  233. type: "checkbox",
  234. value: true,
  235. i18n: {
  236. label: "Improve the YouTube logo"
  237. }
  238. }
  239. },
  240. ini: function () {
  241.  
  242. if (iridium_api.initializeOption.call(this)) {
  243. return;
  244. }
  245.  
  246. if (user_settings.improved_logo) {
  247. document.documentElement.classList.add("iri-improved-logo");
  248. } else {
  249. document.documentElement.classList.remove("iri-improved-logo");
  250. }
  251.  
  252. }
  253. },
  254. {
  255. options: {
  256. thumbnail_preview: {
  257. id: "thumbnail_preview",
  258. section: "general",
  259. sub_section: "thumbnails",
  260. type: "checkbox",
  261. value: false,
  262. i18n: {
  263. label: "Play videos by hovering the thumbnails"
  264. }
  265. },
  266. thumbnail_preview_mute: {
  267. id: "thumbnail_preview_mute",
  268. section: "general",
  269. sub_section: "thumbnails",
  270. type: "checkbox",
  271. value: false,
  272. i18n: {
  273. label: "Shift key toggles audio on video thumbnail playback"
  274. }
  275. }
  276. },
  277. togglePreviewMute: function (event) {
  278.  
  279. var player_api;
  280.  
  281. if (!user_settings.thumbnail_preview_mute) {
  282. return;
  283. }
  284.  
  285. if (event.which === 16 && (player_api = document.getElementById("iri-preview-player"))) {
  286. player_api.handleGlobalKeyDown(77, false);
  287. }
  288.  
  289. },
  290. setPreviewArgs: function (args) {
  291.  
  292. args.autoplay = 1;
  293. args.controls = "0";
  294. args.enablecastapi = "0";
  295. args.iv_load_policy = "3";
  296. args.modestbranding = "1";
  297. args.mute = "1";
  298. args.player_wide = "0";
  299. args.rel = "0";
  300. args.showinfo = "0";
  301. args.vq = "small";
  302.  
  303. args.ad3_module = null;
  304. args.baseUrl = null;
  305. args.eventid = null;
  306. args.iv_endscreen_url = null;
  307. args.ppv_remarketing_url = null;
  308. args.probe_url = null;
  309. args.remarketing_url = null;
  310. args.videostats_playback_base_url = null;
  311.  
  312. },
  313. iniPreview: function (context, event) {
  314.  
  315. var i;
  316. var args;
  317. var temp;
  318. var config;
  319. var data_list;
  320. var player_api;
  321.  
  322. args = {};
  323. data_list = event.target.responseText.split("&");
  324.  
  325. for (i = 0; i < data_list.length; i++) {
  326.  
  327. temp = data_list[i].split("=");
  328. args[temp[0]] = window.decodeURIComponent(temp[1]);
  329.  
  330. }
  331.  
  332. context.setPreviewArgs(args);
  333.  
  334. config = JSON.parse(JSON.stringify(window.yt.config_.FILLER_DATA.player));
  335. config.args = args;
  336. config.attrs.id = "iri-preview-player";
  337.  
  338. window.yt.player.Application.create("iri-video-preview", config);
  339.  
  340. if (player_api = document.getElementById("iri-preview-player")) {
  341.  
  342. if (player_api.setVolume) {
  343. player_api.setVolume(50);
  344. }
  345.  
  346. if (player_api.setSizeStyle) {
  347. player_api.setSizeStyle(false, true);
  348. }
  349.  
  350. }
  351.  
  352. if (document.documentElement.classList.contains("iri-always-visible")) {
  353. if (player_api = document.getElementById("movie_player")) {
  354. if (player_api.setSizeStyle) {
  355. player_api.setSizeStyle(false, true);
  356. }
  357. }
  358. }
  359.  
  360. },
  361. getPreviewArgs: function (video_id) {
  362.  
  363. var sts;
  364. var xhr;
  365. var params;
  366. var context;
  367.  
  368. context = this;
  369. sts = window.yt.config_.FILLER_DATA.player.sts;
  370. params =
  371. "video_id=" + video_id + "&" +
  372. "sts=" + sts + "&" +
  373. "ps=gaming" + "&" +
  374. "el=detailpage" + "&" +
  375. "c=WEB_GAMING" + "&" +
  376. "cplayer=UNIPLAYER" + "&" +
  377. "mute=true" + "&" +
  378. "authuser=0";
  379.  
  380. xhr = new XMLHttpRequest();
  381. xhr.addEventListener("load", function (event) {
  382. context.iniPreview(context, event);
  383. });
  384. xhr.open("GET", "/get_video_info?" + params, true);
  385. xhr.send();
  386.  
  387. return xhr;
  388.  
  389. },
  390. endPreviewContainer: function (event, container, listener, xhr, timer, context, video_container, clicked) {
  391.  
  392. if (clicked || !container.parentNode.contains(event.toElement || event.relatedTarget)) {
  393.  
  394. document.removeEventListener("keydown", context.togglePreviewMute, false);
  395.  
  396. container.parentNode.removeEventListener("click", listener, false);
  397. container.parentNode.removeEventListener("mouseleave", listener, false);
  398.  
  399. if (timer) {
  400. window.clearInterval(timer);
  401. }
  402.  
  403. if (video_container = document.getElementById("iri-video-preview")) {
  404.  
  405. if (xhr) {
  406. xhr.abort();
  407. }
  408.  
  409. if (iridium_api.checkIfExists("firstChild.destroy", video_container)) {
  410. video_container.firstChild.destroy();
  411. }
  412. }
  413. }
  414.  
  415. },
  416. iniPreviewContainer: function (event) {
  417.  
  418. var xhr;
  419. var timer;
  420. var context;
  421. var video_id;
  422. var container;
  423. var video_container;
  424. var moving_thumbnail;
  425. var player_container;
  426. var player_manager_api;
  427.  
  428. moving_thumbnail = event.target.querySelector("#mouseover-overlay");
  429.  
  430. if (!user_settings.thumbnail_preview) {
  431.  
  432. if (moving_thumbnail) {
  433. moving_thumbnail.removeAttribute("style");
  434. }
  435.  
  436. return;
  437.  
  438. }
  439.  
  440. container = event.target;
  441.  
  442. if (container.tagName === "YTD-THUMBNAIL" && (container = event.target.querySelector("yt-img-shadow"))) {
  443. if ((video_id = iridium_api.checkIfExists("dataHost.data.videoId", container)) && !container.querySelector("#iri-preview-player")) {
  444.  
  445. context = this;
  446.  
  447. if (moving_thumbnail) {
  448. moving_thumbnail.setAttribute("style", "display:none");
  449. }
  450.  
  451. if (!(video_container = document.getElementById("iri-video-preview"))) {
  452.  
  453. video_container = document.createElement("iri-video-preview");
  454. video_container.id = "iri-video-preview";
  455. video_container.className = "ytp-small-mode";
  456.  
  457. }
  458.  
  459. if (video_container.parentNode !== container) {
  460. container.appendChild(video_container);
  461. }
  462.  
  463. if (iridium_api.checkIfExists("yt.player.Application.create")) {
  464. xhr = this.getPreviewArgs(video_id);
  465. } else {
  466.  
  467. if (player_manager_api = document.querySelector("yt-player-manager")) {
  468. if (player_container = document.getElementById("player-container")) {
  469. if (iridium_api.checkIfExists("yt.config_.FILLER_DATA.player")) {
  470. player_manager_api["acquireApi"](player_container, window.yt.config_.FILLER_DATA.player);
  471. }
  472. }
  473. }
  474.  
  475. timer = window.setInterval(function () {
  476. if (iridium_api.checkIfExists("yt.player.Application.create")) {
  477.  
  478. window.clearInterval(timer);
  479. xhr = context.getPreviewArgs(video_id);
  480.  
  481. }
  482. });
  483.  
  484. }
  485.  
  486. document.addEventListener("keydown", this.togglePreviewMute, false);
  487.  
  488. container.parentNode.addEventListener("click", function listener(event) {
  489. context.endPreviewContainer(event, container, listener, xhr, timer, context, video_container, true);
  490. }, false);
  491.  
  492. container.parentNode.addEventListener("mouseleave", function listener(event) {
  493. context.endPreviewContainer(event, container, listener, xhr, timer, context);
  494. }, false);
  495.  
  496. }
  497. }
  498.  
  499. },
  500. ini: function () {
  501.  
  502. if (iridium_api.initializeOption.call(this)) {
  503. return;
  504. }
  505.  
  506. document.addEventListener("mouseenter", this.iniPreviewContainer.bind(this), true);
  507.  
  508. }
  509. },
  510. {
  511. options: {
  512. popup_player: {
  513. id: "popup_player",
  514. section: "general",
  515. sub_section: "thumbnails",
  516. type: "checkbox",
  517. value: true,
  518. i18n: {
  519. label: "Enable player pop-up",
  520. button_add_title: "Pop-up"
  521. }
  522. }
  523. },
  524. popUpPlayerMinWidth: 533,
  525. modImportNode: function (original) {
  526.  
  527. var pop_out_button;
  528.  
  529. pop_out_button = document.createElement("template");
  530. pop_out_button.innerHTML =
  531. "<div class='iri-pop-up-player' style='opacity:0'>" +
  532. " <svg viewBox='0 0 24 24' height='16' width='16'>" +
  533. " <path d='M6 0v6H0v18h18v-6h6V0H6z M15 21H3V9h3v9h9V21z M21 15h-3h-3H9V9V6V3h12V15z'/>" +
  534. " </svg>" +
  535. " <div class='iri-tooltip' data-locale='text|button_add_title'></div>" +
  536. "</div>";
  537. pop_out_button = pop_out_button.content;
  538. iridium_api.applyText(pop_out_button, i18n.popup_player);
  539.  
  540. return function (externalNode, deep) {
  541.  
  542. var node;
  543. var container;
  544.  
  545. if (!user_settings.popup_player) {
  546. return original.apply(this, arguments);
  547. }
  548.  
  549. node = externalNode.firstElementChild;
  550.  
  551. if (node) {
  552. if (node.id === "thumbnail" || node.id === "img") {
  553.  
  554. container = node.id === "img" ? node.parentNode : node;
  555.  
  556. if (!container.querySelector(".iri-pop-up-player")) {
  557. container.appendChild(pop_out_button.cloneNode(true));
  558. }
  559.  
  560. }
  561. }
  562.  
  563. return original.apply(this, arguments);
  564.  
  565. };
  566.  
  567. },
  568. resumePlayback: function () {
  569.  
  570. var temp;
  571. var player_api;
  572.  
  573. if (window.location.pathname === "/watch") {
  574. if (player_api = document.getElementById("movie_player")) {
  575. if (temp = this.document.querySelector("video")) {
  576.  
  577. if (!isNaN(temp.duration) && temp.currentTime < temp.duration) {
  578.  
  579. temp = temp.currentTime;
  580. player_api.seekTo(temp);
  581.  
  582. }
  583.  
  584. }
  585. }
  586. }
  587.  
  588. },
  589. popUpPlayer: function (event, url) {
  590.  
  591. var top;
  592. var left;
  593. var video;
  594. var width;
  595. var height;
  596. var pop_up;
  597. var pop_up_url;
  598. var player_api;
  599. var current_config;
  600.  
  601. width = user_settings.popup_player_size || this.popUpPlayerMinWidth;
  602. height = Math.round(width / (16 / 9));
  603. left = event.screenX - (width / 2);
  604. top = event.screenY - 15;
  605. video = document.querySelector("video");
  606. pop_up_url = url || window.location.href.split(/&t=[0-9]+|#t=[0-9]+|&time=[0-9]+/).join("");
  607.  
  608. if (!url && video && video.currentTime && video.currentTime < video.duration) {
  609. if (player_api = document.getElementById("movie_player")) {
  610. if (current_config = iridium_api.getCurrentPageData("player")) {
  611.  
  612. pop_up_url = pop_up_url + "#t=" + video.currentTime;
  613. current_config.args.start = video.currentTime;
  614. current_config.args.cue_player = true;
  615.  
  616. player_api.cueVideoByPlayerVars(current_config.args);
  617.  
  618. }
  619. }
  620. }
  621.  
  622. pop_up = window.open(pop_up_url, "popUpPlayer", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
  623.  
  624. if (!url) {
  625. pop_up.addEventListener("beforeunload", this.resumePlayback.bind(pop_up), false);
  626. }
  627.  
  628. pop_up.focus();
  629.  
  630. },
  631. startPopUpPlayer: function (event) {
  632.  
  633. var url;
  634. var parent;
  635.  
  636. if (!user_settings.popup_player) {
  637. return;
  638. }
  639.  
  640. if (event.type === "message") {
  641. if (event.data.id === user_settings.broadcast_id && event.data.action === "ini-pop-up-player") {
  642.  
  643. event.screenX = event.data.screenX;
  644. event.screenY = event.data.screenY;
  645.  
  646. this.popUpPlayer(event);
  647.  
  648. }
  649. } else if (event.target.className === "iri-pop-up-player") {
  650.  
  651. event.preventDefault();
  652. event.stopPropagation();
  653.  
  654. parent = event.target.parentNode;
  655.  
  656. while (parent) {
  657.  
  658. if (parent.data) {
  659.  
  660. if ("commandMetadata" in parent.data) {
  661. if (url = iridium_api.getSingleObjectByKey(parent.data["commandMetadata"], ["url"])) {
  662. this.popUpPlayer(event, url);
  663. }
  664. }
  665.  
  666. break;
  667.  
  668. }
  669.  
  670. parent = parent.parentNode;
  671.  
  672. }
  673.  
  674. return false;
  675.  
  676. }
  677.  
  678. },
  679. saveNewSize: function () {
  680.  
  681. this.popUpPlayerResizeTimer = null;
  682.  
  683. if (window.innerWidth > this.popUpPlayerMinWidth) {
  684. user_settings.popup_player_size = window.innerWidth;
  685. } else {
  686. user_settings.popup_player_size = this.popUpPlayerMinWidth;
  687. }
  688.  
  689. iridium_api.saveSettings("popup_player_size");
  690.  
  691. },
  692. popUpPlayerResize: function (event) {
  693.  
  694. if (this.popUpPlayerResizeTimer) {
  695. window.clearTimeout(this.popUpPlayerResizeTimer);
  696. }
  697.  
  698. this.popUpPlayerResizeTimer = window.setTimeout(this.saveNewSize.bind(this), 1000);
  699.  
  700. },
  701. ini: function () {
  702.  
  703. if (iridium_api.initializeOption.call(this)) {
  704. return;
  705. }
  706.  
  707. if (iridium_api.isPopUpPlayer) {
  708.  
  709. window.addEventListener("resize", this.popUpPlayerResize.bind(this), false);
  710. document.documentElement.classList.add("iri-pop-up-player-window");
  711.  
  712. } else {
  713.  
  714. document.addEventListener("click", this.startPopUpPlayer.bind(this), true);
  715. window.addEventListener("message", this.startPopUpPlayer.bind(this), false);
  716.  
  717. HTMLDocument.prototype.importNode = this.modImportNode(HTMLDocument.prototype.importNode);
  718.  
  719. }
  720.  
  721. }
  722. },
  723. {
  724. options: {
  725. enable_blacklist: {
  726. id: "enable_blacklist",
  727. section: "general",
  728. sub_section: "blacklist",
  729. type: "checkbox",
  730. value: "true",
  731. i18n: {
  732. label: "Enable blacklist"
  733. }
  734. },
  735. blacklist_settings: {
  736. id: "blacklist_settings",
  737. section: "general",
  738. sub_section: "blacklist",
  739. type: "custom",
  740. value: {},
  741. i18n: {
  742. button_add_title: "Block",
  743. button_edit: "Edit",
  744. button_import: "Import",
  745. button_export: "Export",
  746. button_reset: "Reset",
  747. button_save: "Save",
  748. button_close: "Close",
  749. button_remove: "Remove from blacklist",
  750. placeholder: "Paste your new blacklist here",
  751. confirm_reset: "You are about to reset your blacklist. It is advised to backup your current blacklist before continuing.\n\nDo you wish to continue?\n\n",
  752. reset_success: "Blacklist has been reset.\n\nChanges will be applied after a page refresh.\n\n",
  753. confirm_import: "You are about to override your current blacklist. It is advised to backup your current blacklist before continuing.\n\nDo you wish to continue?\n\n",
  754. import_success: "Your blacklist has been imported with success.\n\nChanges will be applied after a page refresh.\n\n",
  755. import_error: "Your blacklist could not be imported because it appears to be invalid.\n\n"
  756. },
  757. custom: function () {
  758.  
  759. var element;
  760. var element_list;
  761.  
  762. element_list = [];
  763.  
  764. element = document.createElement("button");
  765. element.textContent = i18n.blacklist_settings.button_edit;
  766. element.className = "setting iri-settings-button";
  767. element.addEventListener("click", this.textEditor.bind(this, "edit"), false);
  768.  
  769. element_list.push(element);
  770.  
  771. element = document.createElement("button");
  772. element.textContent = i18n.blacklist_settings.button_import;
  773. element.className = "setting iri-settings-button";
  774. element.addEventListener("click", this.textEditor.bind(this, "import"), false);
  775.  
  776. element_list.push(element);
  777.  
  778. element = document.createElement("button");
  779. element.textContent = i18n.blacklist_settings.button_export;
  780. element.className = "setting iri-settings-button";
  781. element.addEventListener("click", this.textEditor.bind(this, "export"), false);
  782.  
  783. element_list.push(element);
  784.  
  785. element = document.createElement("button");
  786. element.textContent = i18n.blacklist_settings.button_reset;
  787. element.className = "setting iri-settings-button danger";
  788. element.addEventListener("click", this.resetBlacklist.bind(this), false);
  789.  
  790. element_list.push(element);
  791.  
  792. return element_list;
  793.  
  794. },
  795. resetBlacklist: function () {
  796. if (window.confirm(i18n.blacklist_settings.confirm_reset)) {
  797.  
  798. user_settings.blacklist_settings = {};
  799.  
  800. iridium_api.initializeSettings();
  801. iridium_api.saveSettings("blacklist_settings");
  802.  
  803. window.alert(i18n.blacklist_settings.reset_success);
  804.  
  805. }
  806. },
  807. importBlacklist: function () {
  808.  
  809. var editor;
  810. var textarea;
  811.  
  812. if ((textarea = document.getElementById("iridium-textarea")) && window.confirm(i18n.blacklist_settings.confirm_import)) {
  813.  
  814. try {
  815.  
  816. user_settings.blacklist_settings = JSON.parse(textarea.value);
  817.  
  818. iridium_api.saveSettings("blacklist_settings");
  819.  
  820. window.alert(i18n.blacklist_settings.import_success);
  821.  
  822. if (editor = document.getElementById("iridium-text-editor")) {
  823.  
  824. editor.remove();
  825.  
  826. }
  827.  
  828. } catch (error) {
  829.  
  830. window.alert(i18n.blacklist_settings.import_error + error.name + ": " + error.message);
  831.  
  832. }
  833.  
  834. }
  835.  
  836. },
  837. closeEditor: function (editor) {
  838.  
  839. editor.remove();
  840.  
  841. },
  842. textEditor: function (type, event) {
  843.  
  844. var i;
  845. var obj;
  846. var temp;
  847. var editor;
  848. var button;
  849. var channel;
  850. var textarea;
  851. var temp_list;
  852. var blocked_list;
  853. var close_button;
  854. var channel_link;
  855. var buttons_section;
  856.  
  857. if (!(editor = document.getElementById("iridium-text-editor"))) {
  858.  
  859. editor = document.createElement("div");
  860. editor.id = "iridium-text-editor";
  861.  
  862. document.body.appendChild(editor);
  863.  
  864. } else {
  865. editor.textContent = "";
  866. }
  867.  
  868. buttons_section = document.createElement("div");
  869. buttons_section.id = "buttons-section";
  870.  
  871. editor.appendChild(buttons_section);
  872.  
  873. if (type === "import" || type === "export") {
  874.  
  875. textarea = document.createElement("textarea");
  876. textarea.id = "iridium-textarea";
  877. textarea.setAttribute("spellcheck", "false");
  878.  
  879. if (type === "import") {
  880.  
  881. textarea.setAttribute("placeholder", i18n.blacklist_settings.placeholder);
  882.  
  883. button = document.createElement("button");
  884. button.textContent = i18n.blacklist_settings.button_save;
  885. button.className = "iri-settings-button";
  886. button.addEventListener("click", this.importBlacklist.bind(this));
  887.  
  888. buttons_section.appendChild(button);
  889.  
  890. } else {
  891. textarea.value = JSON.stringify(user_settings.blacklist_settings, null, 4);
  892. }
  893.  
  894. editor.appendChild(textarea);
  895.  
  896. } else if (type === "edit") {
  897.  
  898. blocked_list = document.createElement("div");
  899. blocked_list.id = "iridium-blacklist";
  900.  
  901. temp = Object.keys(user_settings.blacklist_settings);
  902. temp_list = [];
  903.  
  904. for (i = 0; i < temp.length; i++) {
  905.  
  906. obj = {};
  907. obj[temp[i]] = user_settings.blacklist_settings[temp[i]];
  908.  
  909. temp_list.push([
  910. temp[i],
  911. user_settings.blacklist_settings[temp[i]]
  912. ]);
  913.  
  914. }
  915.  
  916. temp_list = temp_list.sort(function (previous, next) {
  917. return previous[1].localeCompare(next[1]);
  918. });
  919.  
  920. for (i = 0; i < temp_list.length; i++) {
  921.  
  922. channel = document.createElement("template");
  923. channel.innerHTML =
  924. "<div class='iri-blacklist-channel'>" +
  925. " <button class='close' data-locale='title|button_remove'>" +
  926. " <svg viewBox='0 0 10 10' height='10' width='10'>" +
  927. " <polygon points='10 1.4 8.6 0 5 3.6 1.4 0 0 1.4 3.6 5 0 8.6 1.4 10 5 6.4 8.6 10 10 8.6 6.4 5'/>" +
  928. " </svg>" +
  929. " </button><a target='_blank'></a>" +
  930. "</div>";
  931. channel = channel.content;
  932. iridium_api.applyText(channel, i18n.blacklist_settings);
  933. channel.firstChild.data = true;
  934.  
  935. channel_link = channel.querySelector("a");
  936. channel_link.href = "/channel/" + temp_list[i][0];
  937. channel_link.textContent = temp_list[i][1];
  938.  
  939. close_button = channel.querySelector(".close");
  940. close_button.container = channel.firstChild;
  941. close_button.ucid = temp_list[i][0];
  942. close_button.addEventListener("click", function (event) {
  943.  
  944. event.target.container.remove();
  945. delete user_settings.blacklist_settings[event.target.ucid];
  946.  
  947. iridium_api.saveSettings("blacklist_settings");
  948.  
  949. }, false);
  950.  
  951. blocked_list.appendChild(channel);
  952.  
  953. }
  954.  
  955. editor.appendChild(blocked_list);
  956.  
  957. }
  958.  
  959. button = document.createElement("button");
  960. button.textContent = i18n.blacklist_settings.button_close;
  961. button.className = "iri-settings-button";
  962. button.addEventListener("click", this.closeEditor.bind(this, editor), false);
  963.  
  964. buttons_section.appendChild(button);
  965.  
  966. }
  967. }
  968. },
  969. tag_list: [
  970. "YTD-COMPACT-LINK-RENDERER",
  971. "YTD-COMPACT-PLAYLIST-RENDERER",
  972. "YTD-COMPACT-PROMOTED-VIDEO-RENDERER",
  973. "YTD-COMPACT-RADIO-RENDERER",
  974. "YTD-COMPACT-VIDEO-RENDERER",
  975. "YTD-GRID-CHANNEL-RENDERER",
  976. "YTD-GRID-MOVIE-PLAYLIST-RENDERER",
  977. "YTD-GRID-MOVIE-RENDERER",
  978. "YTD-GRID-PLAYLIST-RENDERER",
  979. "YTD-GRID-RADIO-RENDERER",
  980. "YTD-GRID-RENDERER",
  981. "YTD-GRID-SHOW-RENDERER",
  982. "YTD-GRID-VIDEO-RENDERER",
  983. "YTD-CHANNEL-RENDERER",
  984. "YTD-MOVIE-RENDERER",
  985. "YTD-PLAYLIST-RENDERER",
  986. "YTD-RADIO-RENDERER",
  987. "YTD-SHOW-RENDERER",
  988. "YTD-VIDEO-RENDERER"
  989. ],
  990. allowedBlacklistPage: function () {
  991. return /(\/live$)|^\/($|feed\/(?!subscriptions)|watch|results|shared)/.test(window.location.pathname);
  992. },
  993. hasContainers: function () {
  994. return window.location.pathname.match(/^\/(?:(?:|results)$|feed\/)/);
  995. },
  996. clearList: function (obj) {
  997.  
  998. var i;
  999. var ids;
  1000. var videos;
  1001. var shelves;
  1002. var sections;
  1003. var shelf_tag;
  1004. var video_tag;
  1005. var section_tag;
  1006.  
  1007. section_tag = [
  1008. "itemSectionRenderer",
  1009. "showingResultsForRenderer",
  1010. "includingResultsForRenderer"
  1011. ];
  1012. shelf_tag = [
  1013. "shelfRenderer",
  1014. "compactAutoplayRenderer"
  1015. ];
  1016. video_tag = [
  1017. "playlistRenderer",
  1018. "channelRenderer",
  1019. "radioRenderer",
  1020. "showRenderer",
  1021. "videoRenderer",
  1022. "gridChannelRenderer",
  1023. "gridMoviePlaylistRenderer",
  1024. "gridMovieRenderer",
  1025. "gridPlaylistRenderer",
  1026. "gridRadioRenderer",
  1027. "gridShowRenderer",
  1028. "gridVideoRenderer",
  1029. "compactVideoRenderer",
  1030. "compactPlaylistRenderer",
  1031. "compactPromotedVideoRenderer",
  1032. "playlistPanelVideoRenderer"
  1033. ];
  1034.  
  1035. videos = iridium_api.getObjectByKey(obj, video_tag);
  1036.  
  1037. for (i = 0; i < videos.length; i++) {
  1038.  
  1039. ids = iridium_api.getObjectByKey(videos[i].target, ["browseId"], function (string) {
  1040. return string.indexOf("UC") === 0;
  1041. });
  1042.  
  1043. if (ids[0] && user_settings.blacklist_settings[ids[0].target["browseId"]]) {
  1044. videos[i].list.splice(videos[i].list.indexOf(videos[i].target), 1);
  1045. }
  1046.  
  1047. }
  1048.  
  1049. shelves = iridium_api.getObjectByKey(obj, shelf_tag);
  1050.  
  1051. for (i = 0; i < shelves.length; i++) {
  1052.  
  1053. videos = iridium_api.getObjectByKey(shelves[i].target, video_tag);
  1054.  
  1055. if (videos.length === 0) {
  1056. shelves[i].list.splice(shelves[i].list.indexOf(shelves[i].target), 1);
  1057. }
  1058.  
  1059. }
  1060.  
  1061. if (this.hasContainers()) {
  1062.  
  1063. sections = iridium_api.getObjectByKey(obj, section_tag);
  1064.  
  1065. for (i = 0; i < sections.length; i++) {
  1066. if (sections[i].target[sections[i].property].contents.length === 0) {
  1067. sections[i].list.splice(sections[i].list.indexOf(sections[i].target), 1);
  1068. }
  1069. }
  1070.  
  1071. }
  1072.  
  1073. },
  1074. modOnDone: function (original) {
  1075.  
  1076. var context = this;
  1077.  
  1078. return function (data) {
  1079.  
  1080. context.clearList(data);
  1081.  
  1082. return original.apply(this, arguments);
  1083.  
  1084. };
  1085.  
  1086. },
  1087. getEmptyContainers: function () {
  1088.  
  1089. var i;
  1090. var temp;
  1091. var shelf;
  1092. var container;
  1093. var container_nodes;
  1094.  
  1095. container_nodes = "#contents ytd-item-section-renderer, #contents ytd-shelf-renderer";
  1096. container = document.querySelectorAll(container_nodes);
  1097.  
  1098. for (i = 0; i < container.length; i++) {
  1099.  
  1100. shelf = container[i].querySelector("yt-horizontal-list-renderer");
  1101.  
  1102. if (shelf && (shelf.hasAttribute("at-start") || shelf.hasAttribute("at-end"))) {
  1103. shelf.fillRemainingListItems();
  1104. }
  1105.  
  1106. temp = container[i].querySelector(this.tag_list.join(","));
  1107.  
  1108. if (!temp) {
  1109. container[i].remove();
  1110. }
  1111.  
  1112. }
  1113.  
  1114. window.dispatchEvent(new Event("resize"));
  1115.  
  1116. },
  1117. getContainers: function () {
  1118.  
  1119. var i;
  1120. var ucid;
  1121. var container;
  1122. var container_nodes;
  1123.  
  1124. container_nodes = "#contents ytd-item-section-renderer, #contents ytd-shelf-renderer";
  1125. container = document.querySelectorAll(container_nodes);
  1126.  
  1127. for (i = 0; i < container.length; i++) {
  1128.  
  1129. ucid = iridium_api.getObjectByKey(container[i].data, ["browseId"], function (string) {
  1130. return string.indexOf("UC") === 0;
  1131. });
  1132.  
  1133. if (ucid[0] && ucid.length === 1 && ucid[0].target.browseId) {
  1134. if (user_settings.blacklist_settings[ucid]) {
  1135. container[i].remove();
  1136. }
  1137. }
  1138.  
  1139. }
  1140.  
  1141. },
  1142. getVideos: function () {
  1143.  
  1144. var i;
  1145. var temp;
  1146. var ucid;
  1147. var child;
  1148. var parent;
  1149. var videos;
  1150. var remove;
  1151. var up_next;
  1152.  
  1153. remove = [];
  1154. up_next = document.querySelector("ytd-compact-autoplay-renderer");
  1155. videos = document.querySelectorAll(this.tag_list.join(","));
  1156.  
  1157. for (i = 0; i < videos.length; i++) {
  1158.  
  1159. if (videos[i].data) {
  1160. temp = videos[i];
  1161. }
  1162.  
  1163. if (temp && temp.data) {
  1164.  
  1165. ucid = iridium_api.getObjectByKey(temp.data, ["browseId"], function (string) {
  1166. return string.indexOf("UC") === 0;
  1167. });
  1168.  
  1169. if (ucid[0] && ucid[0].target.browseId) {
  1170. ucid = ucid[0].target.browseId;
  1171. }
  1172.  
  1173. }
  1174.  
  1175. if (ucid) {
  1176. if (user_settings.blacklist_settings[ucid]) {
  1177.  
  1178. if (up_next && up_next.contains(videos[i])) {
  1179.  
  1180. if (up_next.tagName === "YTD-COMPACT-AUTOPLAY-RENDERER") {
  1181. up_next.remove();
  1182. } else {
  1183.  
  1184. up_next.parentNode.remove();
  1185. up_next = document.querySelector(".watch-sidebar-separation-line");
  1186.  
  1187. if (up_next) {
  1188. up_next.remove();
  1189. }
  1190.  
  1191. }
  1192.  
  1193. } else {
  1194. remove.push(videos[i]);
  1195. }
  1196.  
  1197. }
  1198. }
  1199.  
  1200. }
  1201.  
  1202. if (remove.length) {
  1203.  
  1204. for (i = 0; i < remove.length; i++) {
  1205.  
  1206. child = remove[i];
  1207.  
  1208. while (child) {
  1209.  
  1210. parent = child.parentNode;
  1211.  
  1212. if (parent.childElementCount > 1 || parent.id === "contents" || parent.id === "items") {
  1213.  
  1214. child.remove();
  1215. break;
  1216.  
  1217. }
  1218.  
  1219. child = parent;
  1220.  
  1221. }
  1222.  
  1223. }
  1224.  
  1225. if (!this.hasContainers()) {
  1226. window.dispatchEvent(new Event("resize"));
  1227. }
  1228.  
  1229. }
  1230.  
  1231. },
  1232. modImportNode: function (original) {
  1233.  
  1234. var blacklist_button;
  1235.  
  1236. blacklist_button = document.createElement("template");
  1237. blacklist_button.innerHTML =
  1238. "<div class='iri-add-to-blacklist' style='opacity:0'>" +
  1239. " <svg viewBox='0 0 24 24' height='16' width='16'>" +
  1240. " <polygon points='24 2.1 21.9 0 12 9.9 2.1 0 0 2.1 9.9 12 0 21.9 2.1 24 12 14.1 21.9 24 24 21.9 14.1 12'/>" +
  1241. " </svg>" +
  1242. " <div class='iri-tooltip' data-locale='text|button_add_title'></div>" +
  1243. "</div>";
  1244. blacklist_button = blacklist_button.content;
  1245. iridium_api.applyText(blacklist_button, i18n.blacklist_settings);
  1246.  
  1247. return function (externalNode, deep) {
  1248.  
  1249. var node;
  1250. var container;
  1251.  
  1252. if (!user_settings.enable_blacklist) {
  1253. return original.apply(this, arguments);
  1254. }
  1255.  
  1256. node = externalNode.firstElementChild;
  1257.  
  1258. if (node) {
  1259. if (node.id === "thumbnail" || node.id === "img") {
  1260.  
  1261. container = node.id === "img" ? node.parentNode : node;
  1262.  
  1263. if (!container.querySelector(".iri-add-to-blacklist")) {
  1264. container.appendChild(blacklist_button.cloneNode(true));
  1265. }
  1266. }
  1267. }
  1268.  
  1269. return original.apply(this, arguments);
  1270.  
  1271. };
  1272.  
  1273. },
  1274. applyBlacklist: function () {
  1275.  
  1276. var hasContainers;
  1277.  
  1278. if (!this.allowedBlacklistPage()) {
  1279. return;
  1280. }
  1281.  
  1282. hasContainers = this.hasContainers();
  1283.  
  1284. if (hasContainers) {
  1285. this.getContainers();
  1286. }
  1287.  
  1288. this.getVideos();
  1289.  
  1290. if (hasContainers) {
  1291. this.getEmptyContainers();
  1292. }
  1293.  
  1294. },
  1295. addToBlacklist: function (event) {
  1296.  
  1297. var i;
  1298. var ucid;
  1299. var brand;
  1300. var parent;
  1301.  
  1302. if (!user_settings.enable_blacklist) {
  1303. return;
  1304. }
  1305.  
  1306. if (event.target.className === "iri-add-to-blacklist") {
  1307.  
  1308. event.preventDefault();
  1309. event.stopPropagation();
  1310.  
  1311. parent = event.target.parentNode;
  1312.  
  1313. while (parent) {
  1314.  
  1315. if (this.tag_list.indexOf(parent.tagName) > -1) {
  1316.  
  1317. if (parent.data) {
  1318.  
  1319. ucid = iridium_api.getObjectByKey(parent.data, ["browseId"], function (string) {
  1320. return string.indexOf("UC") === 0;
  1321. });
  1322.  
  1323. for (i = 0; i < ucid.length; i++) {
  1324. if (ucid[i] && ucid[i].target && ucid[i].target.browseId) {
  1325. if (ucid[i].list && ucid[i].list[0] && ucid[i].list[0].text) {
  1326.  
  1327. brand = ucid[i].list[0].text;
  1328. ucid = ucid[i].target.browseId;
  1329.  
  1330. break;
  1331.  
  1332. }
  1333. }
  1334. }
  1335.  
  1336. }
  1337.  
  1338. break;
  1339.  
  1340. }
  1341.  
  1342. parent = parent.parentNode;
  1343.  
  1344. }
  1345.  
  1346. if (ucid && brand) {
  1347.  
  1348. if (user_settings.blacklist_settings.constructor.name !== "Object") {
  1349. user_settings.blacklist_settings = {};
  1350. }
  1351.  
  1352. user_settings.blacklist_settings[ucid] = brand;
  1353.  
  1354. iridium_api.saveSettings("blacklist_settings");
  1355.  
  1356. this.applyBlacklist();
  1357.  
  1358. }
  1359.  
  1360. return false;
  1361.  
  1362. }
  1363.  
  1364. },
  1365. iniBlacklist: function () {
  1366.  
  1367. if (user_settings.enable_blacklist && this.allowedBlacklistPage()) {
  1368. document.documentElement.classList.add("iri-blacklist-allowed");
  1369. } else {
  1370. document.documentElement.classList.remove("iri-blacklist-allowed");
  1371. }
  1372.  
  1373. },
  1374. ini: function () {
  1375.  
  1376. var context;
  1377. var iniBlacklistListener;
  1378.  
  1379. if (iridium_api.initializeOption.call(this)) {
  1380. return;
  1381. }
  1382.  
  1383. iniBlacklistListener = this.iniBlacklist.bind(this);
  1384.  
  1385. document.addEventListener("readystatechange", iniBlacklistListener, false);
  1386. document.addEventListener("yt-page-data-fetched", iniBlacklistListener, false);
  1387. document.addEventListener("click", this.addToBlacklist.bind(this), true);
  1388.  
  1389. HTMLDocument.prototype.importNode = this.modImportNode(HTMLDocument.prototype.importNode);
  1390.  
  1391. context = this;
  1392.  
  1393. Object.defineProperties(Object.prototype, {
  1394. ytInitialData: {
  1395. set: function (data) {
  1396. this._ytInitialData = data;
  1397. },
  1398. get: function () {
  1399.  
  1400. if (user_settings.enable_blacklist && context.allowedBlacklistPage()) {
  1401. context.clearList(this._ytInitialData);
  1402. }
  1403.  
  1404. return this._ytInitialData;
  1405.  
  1406. }
  1407. },
  1408. onDone: {
  1409. set: function (data) {
  1410. this._onDone = data;
  1411. },
  1412. get: function () {
  1413.  
  1414. if (user_settings.enable_blacklist && context.allowedBlacklistPage()) {
  1415. return context.modOnDone(this._onDone);
  1416. }
  1417.  
  1418. return this._onDone;
  1419.  
  1420. }
  1421. }
  1422. });
  1423.  
  1424. }
  1425. },
  1426. {
  1427. options: {
  1428. channel_video_count: {
  1429. id: "channel_video_count",
  1430. section: "video",
  1431. sub_section: "general",
  1432. type: "checkbox",
  1433. value: true,
  1434. i18n: {
  1435. label: "Display uploaded videos number"
  1436. }
  1437. },
  1438. channel_video_time: {
  1439. id: "channel_video_time",
  1440. section: "video",
  1441. sub_section: "general",
  1442. type: "checkbox",
  1443. value: true,
  1444. i18n: {
  1445. label: "Display how long the video was uploaded"
  1446. }
  1447. }
  1448. },
  1449. removeVideoCount: function (listener) {
  1450.  
  1451. var xhr;
  1452. var video_count;
  1453. var video_count_dot;
  1454.  
  1455. delete this.addVideoCount.fetching;
  1456.  
  1457. document.removeEventListener("yt-navigate-finish", listener, false);
  1458.  
  1459. xhr = this.removeVideoCount.xhr;
  1460.  
  1461. if (xhr && xhr.abort) {
  1462.  
  1463. xhr.abort();
  1464.  
  1465. delete this.removeVideoCount.xhr;
  1466.  
  1467. }
  1468.  
  1469. if (video_count_dot = document.querySelector("span.iri-video-count")) {
  1470. video_count_dot.remove();
  1471. }
  1472.  
  1473. if (video_count = document.getElementById("iri-video-count")) {
  1474. video_count.remove();
  1475. }
  1476.  
  1477. },
  1478. addVideoCount: function (channel_url, event) {
  1479.  
  1480. var i;
  1481. var page_data;
  1482. var count_match;
  1483. var script_list;
  1484. var video_count;
  1485. var playlist_data;
  1486. var video_count_dot;
  1487. var owner_container;
  1488.  
  1489. delete this.addVideoCount.fetching;
  1490.  
  1491. script_list = event.target ? event.target.response.querySelectorAll("script") : [];
  1492.  
  1493. for (i = 0; i < script_list.length; i++) {
  1494. if (page_data = script_list[i].textContent.match(/window\["ytInitialData"] = ({[\w\W]+});/)) {
  1495. if (page_data = JSON.parse(page_data[1], null, true)) {
  1496.  
  1497. playlist_data = iridium_api.getObjectByKey(page_data.sidebar, ["playlistSidebarPrimaryInfoRenderer"]);
  1498.  
  1499. for (i = 0; i < playlist_data.length; i++) {
  1500. if (iridium_api.checkIfExists("target.playlistSidebarPrimaryInfoRenderer.stats", playlist_data[i])) {
  1501.  
  1502. count_match = iridium_api.getObjectByKey(playlist_data[i].target.playlistSidebarPrimaryInfoRenderer.stats, ["text", "simpleText"]);
  1503.  
  1504. if (count_match.length > 0 && (owner_container = document.getElementById("owner-container"))) {
  1505.  
  1506. count_match = count_match[0].target.text || count_match[0].target.simpleText;
  1507.  
  1508. video_count_dot = document.createElement("span");
  1509. video_count_dot.textContent = " • ";
  1510. video_count_dot.className = "iri-video-count";
  1511.  
  1512. video_count = document.createElement("a");
  1513. video_count.id = "iri-video-count";
  1514. video_count.textContent = count_match;
  1515. video_count.className = "yt-simple-endpoint iri-video-count";
  1516. video_count.setAttribute("href", channel_url + "/videos");
  1517. video_count.data = {
  1518. commandMetadata: {
  1519. webCommandMetadata: {
  1520. url: channel_url + "/videos"
  1521. }
  1522. },
  1523. urlEndpoint: {
  1524. url: channel_url + "/videos"
  1525. }
  1526. };
  1527.  
  1528. owner_container.appendChild(video_count_dot);
  1529. owner_container.appendChild(video_count);
  1530.  
  1531. owner_container.channel_url = channel_url;
  1532. owner_container.video_count = count_match;
  1533.  
  1534. }
  1535.  
  1536. break;
  1537.  
  1538. }
  1539. }
  1540.  
  1541. break;
  1542.  
  1543. }
  1544. }
  1545. }
  1546.  
  1547. },
  1548. removeVideoTime: function (listener) {
  1549.  
  1550. var xhr;
  1551. var time_container;
  1552.  
  1553. delete this.addVideoTime.fetching;
  1554.  
  1555. document.removeEventListener("yt-navigate-finish", listener, false);
  1556.  
  1557. xhr = this.removeVideoTime.xhr;
  1558.  
  1559. if (xhr && xhr.abort) {
  1560.  
  1561. xhr.abort();
  1562.  
  1563. delete this.removeVideoTime.xhr;
  1564.  
  1565. }
  1566.  
  1567. if (time_container = document.getElementById("iri-video-time")) {
  1568. time_container.remove();
  1569. }
  1570.  
  1571. },
  1572. addVideoTime: function (published_date, event) {
  1573.  
  1574. var i;
  1575. var page_data;
  1576. var video_data;
  1577. var script_list;
  1578. var time_container;
  1579.  
  1580. delete this.addVideoTime.fetching;
  1581.  
  1582. script_list = event.target.response.querySelectorAll("script");
  1583.  
  1584. for (i = 0; i < script_list.length; i++) {
  1585. if (page_data = script_list[i].textContent.match(/window\["ytInitialData"] = ({[\w\W]+});/)) {
  1586. if (page_data = JSON.parse(page_data[1], null, true)) {
  1587.  
  1588. video_data = iridium_api.getObjectByKey(page_data.contents, ["videoId"], function (video_id, obj) {
  1589.  
  1590. var current_video_id;
  1591.  
  1592. if (obj && obj.publishedTimeText) {
  1593. if (current_video_id = window.location.href.match(iridium_api.videoIdPattern)) {
  1594. if (current_video_id = current_video_id[1]) {
  1595. return video_id === current_video_id;
  1596. }
  1597. }
  1598. }
  1599.  
  1600. });
  1601.  
  1602. for (i = 0; i < video_data.length; i++) {
  1603. if (video_data[i].target.publishedTimeText && video_data[i].target.publishedTimeText.simpleText) {
  1604.  
  1605. time_container = document.createElement("span");
  1606. time_container.id = "iri-video-time";
  1607. time_container.textContent = " • " + video_data[i].target.publishedTimeText.simpleText;
  1608.  
  1609. published_date.appendChild(time_container);
  1610.  
  1611. break;
  1612.  
  1613. }
  1614. }
  1615.  
  1616. break;
  1617.  
  1618. }
  1619. }
  1620. }
  1621.  
  1622. },
  1623. loadStart: function () {
  1624.  
  1625. var xhr;
  1626. var context;
  1627. var video_id;
  1628. var channel_id;
  1629. var channel_url;
  1630. var upload_info;
  1631. var watch_page_active;
  1632.  
  1633. watch_page_active = document.querySelector("ytd-watch:not([hidden]), ytd-watch-flexy:not([hidden])");
  1634.  
  1635. if (watch_page_active) {
  1636.  
  1637. if (channel_url = document.querySelector("#owner-name a")) {
  1638.  
  1639. channel_url = channel_url.getAttribute("href").split(/\/videos/)[0];
  1640. channel_id = channel_url.match(/UC([a-z0-9-_]{22})/i);
  1641.  
  1642. } else if (channel_id = iridium_api.getSingleObjectByKey(window.ytplayer, "ucid")) {
  1643.  
  1644. channel_url = "/channel/" + channel_id;
  1645. channel_id = channel_url.match(/UC([a-z0-9-_]{22})/i);
  1646.  
  1647. } else {
  1648.  
  1649. return;
  1650.  
  1651. }
  1652.  
  1653. if (channel_id && (channel_id = channel_id[1])) {
  1654. if (user_settings.channel_video_count) {
  1655. if (!this.addVideoCount.fetching) {
  1656. if (document.getElementById("owner-container")) {
  1657. if (!document.getElementById("iri-video-count")) {
  1658.  
  1659. if (this.removeVideoCount.xhr) {
  1660. this.removeVideoCount.xhr.abort();
  1661. }
  1662.  
  1663. this.addVideoCount.fetching = true;
  1664.  
  1665. xhr = new XMLHttpRequest();
  1666. xhr.addEventListener("load", this.addVideoCount.bind(this, channel_url));
  1667. xhr.open("GET", "/playlist?list=UU" + channel_id, true);
  1668. xhr.responseType = "document";
  1669. xhr.send();
  1670.  
  1671. this.removeVideoCount.xhr = xhr;
  1672.  
  1673. context = this;
  1674.  
  1675. document.addEventListener("yt-navigate-finish", function listener() {
  1676. context.removeVideoCount(listener);
  1677. }, false);
  1678.  
  1679. }
  1680. }
  1681. }
  1682. }
  1683.  
  1684. if (user_settings.channel_video_time) {
  1685. if (!this.addVideoTime.fetching) {
  1686. if (upload_info = document.querySelector("#upload-info .date")) {
  1687. if (upload_info.textContent.indexOf("•") === -1) {
  1688. if ((video_id = window.location.href.match(iridium_api.videoIdPattern)) && (video_id = video_id[1])) {
  1689.  
  1690. if (this.removeVideoTime.xhr) {
  1691. this.removeVideoTime.xhr.abort();
  1692. }
  1693.  
  1694. this.addVideoTime.fetching = true;
  1695.  
  1696. xhr = new XMLHttpRequest();
  1697. xhr.addEventListener("load", this.addVideoTime.bind(this, upload_info));
  1698. xhr.open("GET", "/channel/UC" + channel_id + "/search?query=%22" + video_id + "%22", true);
  1699. xhr.responseType = "document";
  1700. xhr.send();
  1701.  
  1702. this.removeVideoTime.xhr = xhr;
  1703.  
  1704. context = this;
  1705.  
  1706. document.addEventListener("yt-navigate-finish", function listener() {
  1707. context.removeVideoTime(listener);
  1708. }, false);
  1709.  
  1710. }
  1711. }
  1712. }
  1713. }
  1714. }
  1715. }
  1716.  
  1717. }
  1718.  
  1719. },
  1720. ini: function () {
  1721.  
  1722. if (iridium_api.initializeOption.call(this)) {
  1723. return;
  1724. }
  1725.  
  1726. window.addEventListener("yt-page-data-updated", this.loadStart.bind(this), true);
  1727.  
  1728. }
  1729. },
  1730. {
  1731. options: {
  1732. playlist_reverse_control: {
  1733. id: "playlist_reverse_control",
  1734. section: "video",
  1735. sub_section: "playlist",
  1736. type: "checkbox",
  1737. value: true,
  1738. i18n: {
  1739. label: "Enable reverse playlist control",
  1740. button_label: "Reverse playlist",
  1741. toggle_on: "Reverse is on",
  1742. toggle_off: "Reverse is off"
  1743. }
  1744. }
  1745. },
  1746. reversePlaylist: function () {
  1747.  
  1748. var i;
  1749. var autoplay;
  1750. var playlist;
  1751. var ytd_watch;
  1752. var yt_navigation_manager;
  1753. var twoColumnWatchNextResults;
  1754.  
  1755. if (ytd_watch = document.querySelector("ytd-watch, ytd-watch-flexy")) {
  1756. if (ytd_watch.data) {
  1757. if (twoColumnWatchNextResults = iridium_api.getSingleObjectByKey(ytd_watch.data, ["twoColumnWatchNextResults"])) {
  1758. if ("playlist" in twoColumnWatchNextResults && "playlist" in (playlist = twoColumnWatchNextResults["playlist"])) {
  1759. if ("contents" in (playlist = playlist["playlist"])) {
  1760.  
  1761. playlist["contents"].reverse();
  1762.  
  1763. if ("currentIndex" in playlist) {
  1764. playlist["currentIndex"] = playlist["totalVideos"] - playlist["currentIndex"] - 1;
  1765. }
  1766.  
  1767. if ("localCurrentIndex" in playlist) {
  1768. playlist["localCurrentIndex"] = playlist["contents"].length - playlist["localCurrentIndex"] - 1;
  1769. }
  1770.  
  1771. if ("autoplay" in twoColumnWatchNextResults && "autoplay" in (autoplay = twoColumnWatchNextResults["autoplay"])) {
  1772. if ("sets" in (autoplay = autoplay["autoplay"])) {
  1773. for (i = 0; i < autoplay["sets"].length; i++) {
  1774. if (autoplay["sets"][i]["previousButtonVideo"] && autoplay["sets"][i]["nextButtonVideo"]) {
  1775.  
  1776. autoplay["sets"][i]["autoplayVideo"] = autoplay["sets"][i]["previousButtonVideo"];
  1777. autoplay["sets"][i]["previousButtonVideo"] = autoplay["sets"][i]["nextButtonVideo"];
  1778. autoplay["sets"][i]["nextButtonVideo"] = autoplay["sets"][i]["autoplayVideo"];
  1779.  
  1780. }
  1781. }
  1782. }
  1783. }
  1784.  
  1785. if ("updatePageData_" in ytd_watch) {
  1786. ytd_watch["updatePageData_"](JSON.parse(JSON.stringify(ytd_watch.data)));
  1787. }
  1788.  
  1789. // timeout temporary workaround for playlist buttons ui not updating after first video changes
  1790. window.setTimeout(function () {
  1791. if (yt_navigation_manager = document.querySelector("yt-navigation-manager")) {
  1792. if ("updatePlayerComponents_" in yt_navigation_manager) {
  1793. yt_navigation_manager["updatePlayerComponents_"](null, autoplay, null, playlist);
  1794. }
  1795. }
  1796. }, 500);
  1797.  
  1798. }
  1799. }
  1800. }
  1801. }
  1802. }
  1803.  
  1804. },
  1805. reverseButtonToggled: function (event) {
  1806. if (event.target.data.isReverseButton) {
  1807.  
  1808. user_settings.playlist_reverse = event.target.data.isToggled;
  1809. iridium_api.saveSettings("playlist_reverse");
  1810. this.reversePlaylist();
  1811.  
  1812. }
  1813. },
  1814. setReverseButtonData: function () {
  1815.  
  1816. var defaultLabel;
  1817. var toggledLabel;
  1818. var notificationActionRenderer;
  1819.  
  1820. this["defaultIcon"].iconType = "REVERSE";
  1821. this["accessibility"].label = i18n.playlist_reverse_control.button_label;
  1822. this.defaultTooltip = i18n.playlist_reverse_control.button_label;
  1823. this.toggledTooltip = i18n.playlist_reverse_control.button_label;
  1824. this.isToggled = user_settings.playlist_reverse;
  1825. this.isReverseButton = true;
  1826.  
  1827. if (defaultLabel = iridium_api.getObjectByKey(this["defaultServiceEndpoint"], ["text"])) {
  1828. if (defaultLabel.length) {
  1829. defaultLabel[0].target.text = i18n.playlist_reverse_control.toggle_on;
  1830. }
  1831. }
  1832.  
  1833. if (toggledLabel = iridium_api.getObjectByKey(this["toggledServiceEndpoint"], ["text"])) {
  1834. if (toggledLabel.length) {
  1835. toggledLabel[0].target.text = i18n.playlist_reverse_control.toggle_off;
  1836. }
  1837. }
  1838.  
  1839. if (defaultLabel = iridium_api.getObjectByKey(this["defaultServiceEndpoint"], ["simpleText"])) {
  1840. if (defaultLabel.length) {
  1841. defaultLabel[0].target.simpleText = i18n.playlist_reverse_control.toggle_on;
  1842. }
  1843. }
  1844.  
  1845. if (toggledLabel = iridium_api.getObjectByKey(this["toggledServiceEndpoint"], ["simpleText"])) {
  1846. if (toggledLabel.length) {
  1847. toggledLabel[0].target.simpleText = i18n.playlist_reverse_control.toggle_off;
  1848. }
  1849. }
  1850.  
  1851. },
  1852. buildReverseButton: function (data) {
  1853.  
  1854. var i;
  1855. var reversePlaylistButton;
  1856.  
  1857. for (i = 0; i < data.length; i++) {
  1858. if ("toggleButtonRenderer" in data[i] && data[i]["toggleButtonRenderer"].isReverseButton) {
  1859. return;
  1860. }
  1861. }
  1862.  
  1863. reversePlaylistButton = JSON.parse(JSON.stringify(data[0]));
  1864.  
  1865. data.push(reversePlaylistButton);
  1866. this.setReverseButtonData.apply(reversePlaylistButton["toggleButtonRenderer"]);
  1867.  
  1868. if (!this.reverseButtonToggledListener) {
  1869.  
  1870. this.reverseButtonToggledListener = this.reverseButtonToggled.bind(this);
  1871.  
  1872. window.addEventListener("yt-toggle-button", this.reverseButtonToggledListener, false);
  1873.  
  1874. }
  1875.  
  1876. if (user_settings.playlist_reverse) {
  1877. this.reversePlaylist();
  1878. }
  1879.  
  1880. },
  1881. createReverseButton: function () {
  1882.  
  1883. var path;
  1884.  
  1885. this.id = "reverse";
  1886.  
  1887. if (path = this.querySelector("path")) {
  1888. path.setAttribute("d", "M6 21l-4-4h3V5h2v12h3L6 21z M19 7v12h-2V7h-3l4-4l4 4H19z");
  1889. }
  1890.  
  1891. },
  1892. modSetMenuData: function (original) {
  1893.  
  1894. var context = this;
  1895.  
  1896. return function (data) {
  1897.  
  1898. var playlistButtons;
  1899. var topLevelButtons;
  1900.  
  1901. if (!data || !data["playlistButtons"]) {
  1902. return original.apply(this, arguments);
  1903. }
  1904.  
  1905. if (playlistButtons = iridium_api.getSingleObjectByKey(data, ["playlistButtons"])) {
  1906. if (topLevelButtons = iridium_api.getSingleObjectByKey(playlistButtons, ["topLevelButtons"])) {
  1907. context.buildReverseButton(topLevelButtons);
  1908. }
  1909. }
  1910.  
  1911. return original.apply(this, arguments);
  1912.  
  1913. };
  1914.  
  1915. },
  1916. interceptYtIcons: function () {
  1917.  
  1918. var loopIcon;
  1919. var reverseIcon;
  1920.  
  1921. if (loopIcon = document.querySelector("g#loop")) {
  1922.  
  1923. reverseIcon = loopIcon.cloneNode(true);
  1924.  
  1925. this.createReverseButton.apply(reverseIcon);
  1926. loopIcon.parentNode.appendChild(reverseIcon);
  1927.  
  1928. document.removeEventListener("readystatechange", this.interceptListener, true);
  1929.  
  1930. }
  1931.  
  1932. },
  1933. interceptImport: function (data) {
  1934.  
  1935. var iconSet;
  1936. var reverseIcon;
  1937.  
  1938. if (data.target.tagName === "LINK" && data.target.rel === "import" && data.target.getAttribute("name")) {
  1939. if (reverseIcon = data.target.import.querySelector("#loop")) {
  1940.  
  1941. iconSet = reverseIcon.parentElement;
  1942. reverseIcon = reverseIcon.cloneNode(true);
  1943.  
  1944. this.createReverseButton.apply(reverseIcon);
  1945. iconSet.appendChild(reverseIcon);
  1946.  
  1947. document.documentElement.removeEventListener("load", this.interceptListener, true);
  1948.  
  1949. this.interceptListener = null;
  1950.  
  1951. }
  1952. }
  1953.  
  1954. },
  1955. ini: function () {
  1956.  
  1957. var context;
  1958.  
  1959. if (iridium_api.initializeOption.call(this)) {
  1960. return;
  1961. }
  1962.  
  1963. if ("import" in document.createElement("link")) {
  1964.  
  1965. this.interceptListener = this.interceptImport.bind(this);
  1966.  
  1967. document.documentElement.addEventListener("load", this.interceptListener, true);
  1968.  
  1969. } else {
  1970.  
  1971. this.interceptListener = this.interceptYtIcons.bind(this);
  1972.  
  1973. document.addEventListener("readystatechange", this.interceptListener, true);
  1974. this.interceptYtIcons();
  1975.  
  1976. }
  1977.  
  1978. context = this;
  1979.  
  1980. Object.defineProperties(Object.prototype, {
  1981. setMenuData_: {
  1982. set: function (data) {
  1983. this._setMenuData_ = data;
  1984. },
  1985. get: function () {
  1986.  
  1987. if (this._setMenuData_) {
  1988. return context.modSetMenuData(this._setMenuData_);
  1989. }
  1990.  
  1991. return this._setMenuData_;
  1992. }
  1993. }
  1994. });
  1995.  
  1996. }
  1997. },
  1998. {
  1999. options: {
  2000. player_quality: {
  2001. id: "player_quality",
  2002. section: "video",
  2003. sub_section: "player",
  2004. type: "dropdown",
  2005. value: "auto",
  2006. i18n: {
  2007. label: "Default video quality:",
  2008. options: [
  2009. "4320p (8k)",
  2010. "2880p (5k)",
  2011. "2160p (4k)",
  2012. "1440p",
  2013. "1080p",
  2014. "720p",
  2015. "480p",
  2016. "360p",
  2017. "240p",
  2018. "144p",
  2019. "Auto"
  2020. ]
  2021. },
  2022. options: [
  2023. "highres",
  2024. "hd2880",
  2025. "hd2160",
  2026. "hd1440",
  2027. "hd1080",
  2028. "hd720",
  2029. "large",
  2030. "medium",
  2031. "small",
  2032. "tiny",
  2033. "auto"
  2034. ]
  2035. },
  2036. player_auto_play: {
  2037. id: "player_auto_play",
  2038. section: "video",
  2039. sub_section: "player",
  2040. type: "checkbox",
  2041. value: false,
  2042. i18n: {
  2043. label: "Play videos automatically"
  2044. }
  2045. },
  2046. channel_trailer_auto_play: {
  2047. id: "channel_trailer_auto_play",
  2048. section: "video",
  2049. sub_section: "channel",
  2050. type: "checkbox",
  2051. value: false,
  2052. i18n: {
  2053. label: "Play channel trailers automatically"
  2054. }
  2055. },
  2056. player_annotations: {
  2057. id: "player_annotations",
  2058. section: "video",
  2059. sub_section: "player",
  2060. type: "checkbox",
  2061. value: false,
  2062. i18n: {
  2063. label: "Allow annotations on videos"
  2064. }
  2065. },
  2066. player_subtitles: {
  2067. id: "player_subtitles",
  2068. section: "video",
  2069. sub_section: "player",
  2070. type: "checkbox",
  2071. value: false,
  2072. i18n: {
  2073. label: "Allow subtitles on videos"
  2074. }
  2075. },
  2076. player_loudness: {
  2077. id: "player_loudness",
  2078. section: "video",
  2079. sub_section: "player",
  2080. type: "checkbox",
  2081. value: false,
  2082. i18n: {
  2083. label: "Allow loudness normalization"
  2084. }
  2085. },
  2086. player_ads: {
  2087. id: "player_ads",
  2088. section: "video",
  2089. sub_section: "player",
  2090. type: "checkbox",
  2091. value: false,
  2092. i18n: {
  2093. label: "Allow ads on videos"
  2094. }
  2095. },
  2096. subscribed_channel_player_ads: {
  2097. id: "subscribed_channel_player_ads",
  2098. section: "video",
  2099. sub_section: "player",
  2100. type: "checkbox",
  2101. value: false,
  2102. i18n: {
  2103. label: "Allow ads only on videos of subscribed channels"
  2104. }
  2105. },
  2106. player_hfr: {
  2107. id: "player_hfr",
  2108. section: "video",
  2109. sub_section: "player",
  2110. type: "checkbox",
  2111. value: true,
  2112. i18n: {
  2113. label: "Allow HFR (60fps) streams"
  2114. }
  2115. },
  2116. player_memorize_size: {
  2117. id: "player_memorize_size",
  2118. section: "video",
  2119. sub_section: "player",
  2120. type: "checkbox",
  2121. value: true,
  2122. i18n: {
  2123. label: "Memorize player size"
  2124. }
  2125. },
  2126. player_memorize_volume: {
  2127. id: "player_memorize_volume",
  2128. section: "video",
  2129. sub_section: "player",
  2130. type: "checkbox",
  2131. value: true,
  2132. i18n: {
  2133. label: "Memorize player volume"
  2134. }
  2135. },
  2136. player_max_res_thumbnail: {
  2137. id: "player_max_res_thumbnail",
  2138. section: "video",
  2139. sub_section: "player",
  2140. type: "checkbox",
  2141. value: true,
  2142. i18n: {
  2143. label: "Force high quality player thumbnail"
  2144. }
  2145. }
  2146. },
  2147. modArgs: function (args) {
  2148.  
  2149. var i;
  2150. var fps;
  2151. var list;
  2152. var key_type;
  2153. var player_response;
  2154. var thumbnail_image;
  2155.  
  2156. if (args.controls !== "0") {
  2157.  
  2158. if (!iridium_api.isPopUpPlayer && this.isChannel() ? !user_settings.channel_trailer_auto_play : !user_settings.player_auto_play) {
  2159.  
  2160. args.autoplay = "0";
  2161. args.suppress_autoplay_on_watch = true;
  2162. args.fflags = args.fflags.replace(/html5_new_autoplay_redux=true/g, "html5_new_autoplay_redux=false");
  2163.  
  2164. }
  2165.  
  2166. }
  2167.  
  2168. if (user_settings.player_max_res_thumbnail) {
  2169. if (args.eventid && args.thumbnail_url) {
  2170.  
  2171. args.iurlmaxres = args.thumbnail_url.replace(/\/[^\/]+$/, "/maxresdefault.jpg");
  2172.  
  2173. thumbnail_image = new Image();
  2174.  
  2175. thumbnail_image.addEventListener("load", this.checkHighQualityThumbnail.bind(this, args.iurlmaxres), false);
  2176.  
  2177. thumbnail_image.src = args.iurlmaxres;
  2178. thumbnail_image = null;
  2179.  
  2180. }
  2181. }
  2182.  
  2183. if (user_settings.subscribed_channel_player_ads ? args.subscribed !== "1" : !user_settings.player_ads) {
  2184.  
  2185. delete args.ad3_module;
  2186.  
  2187. if (args.player_response) {
  2188.  
  2189. player_response = JSON.parse(args.player_response);
  2190.  
  2191. if (player_response && player_response.adPlacements) {
  2192.  
  2193. delete player_response.adPlacements;
  2194. args.player_response = JSON.stringify(player_response);
  2195.  
  2196. }
  2197.  
  2198. }
  2199.  
  2200. }
  2201.  
  2202. if (!user_settings.player_annotations) {
  2203. args.iv_load_policy = "3";
  2204. }
  2205.  
  2206. if (!user_settings.player_loudness) {
  2207.  
  2208. args.loudness = null;
  2209. args.relative_loudness = null;
  2210.  
  2211. delete args.loudness;
  2212. delete args.relative_loudness;
  2213.  
  2214. }
  2215.  
  2216. if (!user_settings.player_subtitles) {
  2217.  
  2218. iridium_api.setStorage(
  2219. "yt-html5-player-modules::subtitlesModuleData::module-enabled",
  2220. "false"
  2221. );
  2222.  
  2223. if (args.caption_audio_tracks) {
  2224. args.caption_audio_tracks = args.caption_audio_tracks.split(/&d=[0-9]|d=[0-9]&/).join("");
  2225. }
  2226.  
  2227. }
  2228.  
  2229. if (!user_settings.player_hfr && args.adaptive_fmts) {
  2230.  
  2231. key_type = args.adaptive_fmts.indexOf(",") > -1 ? "," : "%2C";
  2232. list = args.adaptive_fmts.split(key_type);
  2233.  
  2234. for (i = 0; i < list.length; i++) {
  2235.  
  2236. fps = list[i].split(/fps(?:=|%3D)([0-9]{2})/);
  2237. fps = fps && fps[1];
  2238.  
  2239. if (fps > 30) {
  2240. list.splice(i--, 1);
  2241. }
  2242.  
  2243. }
  2244.  
  2245. args.adaptive_fmts = list.join(key_type);
  2246.  
  2247. }
  2248.  
  2249. if (iridium_api.isPopUpPlayer) {
  2250. args.el = "embedded";
  2251. }
  2252.  
  2253. },
  2254. modVideoByPlayerVars: function (original) {
  2255.  
  2256. var context = this;
  2257.  
  2258. return function (args) {
  2259.  
  2260. var temp;
  2261. var current_config;
  2262. var current_video_id;
  2263.  
  2264. if (!args.eventid || iridium_api.isPopUpPlayer) {
  2265. return original.apply(this, arguments);
  2266. }
  2267.  
  2268. current_config = iridium_api.getCurrentPageData("player");
  2269.  
  2270. if (current_config && current_config.args && !args.cue_player) {
  2271.  
  2272. context.updatePlayerLayout = !!current_config.args.list !== !!args.list;
  2273.  
  2274. if ((current_config.args.eventid === args.eventid || current_config.args.loaderUrl === args.loaderUrl)) {
  2275. if (!document.querySelector(".ended-mode,.unstarted-mode") && (current_video_id = window.location.href.match(iridium_api.videoIdPattern))) {
  2276. if (current_video_id[1] === current_config.args.video_id) {
  2277. return function () {
  2278. };
  2279. }
  2280. }
  2281. }
  2282.  
  2283. }
  2284.  
  2285. context.modArgs(args);
  2286.  
  2287. temp = original.apply(this, arguments);
  2288.  
  2289. if (user_settings.player_quality !== "auto") {
  2290. context.markedForQuality = true;
  2291. }
  2292.  
  2293. context.setPlayerResize();
  2294.  
  2295. return temp;
  2296.  
  2297. };
  2298.  
  2299. },
  2300. modPlayerLoad: function (original) {
  2301.  
  2302. var context = this;
  2303.  
  2304. return function (api_name, config) {
  2305.  
  2306. var temp;
  2307.  
  2308. context.modArgs(config.args);
  2309.  
  2310. temp = original.apply(this, arguments);
  2311.  
  2312. if (user_settings.player_quality !== "auto") {
  2313. context.markedForQuality = true;
  2314. }
  2315.  
  2316. context.setPlayerResize();
  2317.  
  2318. return temp;
  2319.  
  2320. };
  2321.  
  2322. },
  2323. modJSONParse: function (original) {
  2324.  
  2325. var context = this;
  2326.  
  2327. return function (text, reviver, bypass) {
  2328.  
  2329. var temp = original.apply(this, arguments);
  2330.  
  2331. if (!bypass && temp && temp.player && temp.player.args) {
  2332. context.modArgs(temp.player.args);
  2333. }
  2334.  
  2335. return temp;
  2336.  
  2337. };
  2338.  
  2339. },
  2340. modOpen: function (original) {
  2341.  
  2342. var context = this;
  2343.  
  2344. return function (method, url) {
  2345.  
  2346. if (url.match("get_video_info") && !url.match("el=adunit") && !url.match("ps=gaming")) {
  2347. this.addEventListener("readystatechange", context.patchXHR.bind(context));
  2348. }
  2349.  
  2350. return original.apply(this, arguments);
  2351.  
  2352. };
  2353.  
  2354. },
  2355. modParseFromString: function (original) {
  2356.  
  2357. return function () {
  2358.  
  2359. var i;
  2360. var fps;
  2361. var result;
  2362. var streams;
  2363.  
  2364. if (!user_settings.player_hfr) {
  2365.  
  2366. result = original.apply(this, arguments);
  2367. streams = result.getElementsByTagName("Representation");
  2368. i = streams.length;
  2369.  
  2370. while (i--) {
  2371.  
  2372. fps = streams[i].getAttribute("frameRate");
  2373.  
  2374. if (fps > 30) {
  2375. streams[i].remove();
  2376. }
  2377.  
  2378. }
  2379.  
  2380. return result;
  2381.  
  2382. }
  2383.  
  2384. return original.apply(this, arguments);
  2385.  
  2386. };
  2387.  
  2388. },
  2389. setPlayerResize: function () {
  2390.  
  2391. var watch_page_api;
  2392.  
  2393. if (user_settings.player_memorize_size && window.location.pathname === "/watch" && (watch_page_api = document.querySelector("ytd-watch, ytd-watch-flexy"))) {
  2394. try {
  2395. watch_page_api["theaterModeChanged_"](user_settings.theaterMode);
  2396. } catch (ignore) {
  2397. }
  2398. }
  2399.  
  2400. },
  2401. setQuality: function (player_api, quality) {
  2402.  
  2403. var position;
  2404. var max_position;
  2405. var available_qualities;
  2406.  
  2407. if (player_api.getAvailableQualityLevels && (available_qualities = player_api.getAvailableQualityLevels())) {
  2408.  
  2409. if (available_qualities.length === 0) {
  2410. return;
  2411. }
  2412.  
  2413. this.markedForQuality = false;
  2414.  
  2415. if (available_qualities.indexOf(quality) > -1) {
  2416.  
  2417. player_api.setPlaybackQuality(quality);
  2418. player_api.setPlaybackQualityRange(quality);
  2419.  
  2420. } else {
  2421.  
  2422. if ((position = this.options.player_quality.options.indexOf(quality)) > -1) {
  2423.  
  2424. max_position = this.options.player_quality.options.indexOf(available_qualities[0]);
  2425.  
  2426. if (position <= max_position) {
  2427.  
  2428. player_api.setPlaybackQuality(available_qualities[0]);
  2429. player_api.setPlaybackQualityRange(available_qualities[0]);
  2430.  
  2431. } else {
  2432.  
  2433. player_api.setPlaybackQuality(available_qualities[available_qualities.length - 2]);
  2434. player_api.setPlaybackQualityRange(available_qualities[available_qualities.length - 2]);
  2435.  
  2436. }
  2437.  
  2438. }
  2439.  
  2440. }
  2441.  
  2442. }
  2443.  
  2444. },
  2445. checkHighQualityThumbnail: function (thumbnail_url, event) {
  2446.  
  2447. var style_element;
  2448. var thumbnail_container;
  2449.  
  2450. if (event.target.width < 121 && (thumbnail_container = document.querySelector(".ytp-cued-thumbnail-overlay-image"))) {
  2451.  
  2452. if (!(style_element = document.getElementById("style-thumbnail"))) {
  2453.  
  2454. style_element = document.createElement("style");
  2455. style_element.id = "style-thumbnail";
  2456.  
  2457. thumbnail_container.parentNode.insertBefore(style_element, thumbnail_container);
  2458.  
  2459. }
  2460.  
  2461. style_element.textContent =
  2462. ".ytp-cued-thumbnail-overlay-image {" +
  2463. " background-image:url('" + thumbnail_url.replace("maxresdefault", "mqdefault") + "') !important;" +
  2464. "}";
  2465.  
  2466. } else if (style_element = document.getElementById("style-thumbnail")) {
  2467. style_element.textContent = "";
  2468. }
  2469.  
  2470. },
  2471. patchXHR: function (event) {
  2472.  
  2473. var i;
  2474. var temp;
  2475. var temp_list;
  2476. var key_value;
  2477.  
  2478. if (event.target.readyState === 4 && event.target.responseText.match(/eventid=/)) {
  2479.  
  2480. temp_list = {};
  2481. temp = event.target.responseText.split("&");
  2482.  
  2483. for (i = 0; i < temp.length; i++) {
  2484.  
  2485. key_value = temp[i].split("=");
  2486. key_value[1] = key_value[1] === undefined ? "" : key_value[1].replace(/\+/g, "%20");
  2487. temp_list[key_value[0]] = window.decodeURIComponent(key_value[1]);
  2488.  
  2489. }
  2490.  
  2491. this.modArgs(temp_list);
  2492.  
  2493. Object.defineProperty(event.target, "responseText", {writable: true});
  2494.  
  2495. event.target.responseText = "";
  2496. temp = Object.keys(temp_list);
  2497.  
  2498. for (i = 0; i < temp.length; i++) {
  2499.  
  2500. event.target.responseText += temp[i] + "=" + window.encodeURIComponent(temp_list[temp[i]]).replace(/%20/g, "+");
  2501.  
  2502. if (i + 1 < temp.length) {
  2503. event.target.responseText += "&";
  2504. }
  2505.  
  2506. }
  2507.  
  2508. if (user_settings.player_quality !== "auto") {
  2509. this.markedForQuality = true;
  2510. }
  2511.  
  2512. this.setPlayerResize();
  2513.  
  2514. }
  2515.  
  2516. },
  2517. interceptHooks: function (event) {
  2518.  
  2519. if (iridium_api.checkIfExists("yt.player.Application.create")) {
  2520.  
  2521. window.yt.player.Application.create = this.modPlayerLoad(window.yt.player.Application.create);
  2522.  
  2523. document.documentElement.removeEventListener("load", this.fileLoadListener, true);
  2524.  
  2525. this.fileLoadListener = null;
  2526.  
  2527. }
  2528.  
  2529. },
  2530. handleCustoms: function (event) {
  2531.  
  2532. if (typeof event === "object") {
  2533. if (user_settings.player_memorize_volume && user_settings.userVolume !== event.volume) {
  2534.  
  2535. user_settings.userVolume = event.volume;
  2536.  
  2537. iridium_api.saveSettings("userVolume");
  2538.  
  2539. }
  2540. } else {
  2541. if (user_settings.player_memorize_size && user_settings.theaterMode !== event) {
  2542.  
  2543. user_settings.theaterMode = event;
  2544.  
  2545. iridium_api.saveSettings("theaterMode");
  2546.  
  2547. }
  2548. }
  2549.  
  2550. },
  2551. onStateChange: function (event) {
  2552.  
  2553. var player;
  2554.  
  2555. if (this.markedForQuality && (event === 1 || event === 3) && user_settings.player_quality !== "auto" && (player = document.getElementById("movie_player"))) {
  2556.  
  2557. this.setQuality(player, user_settings.player_quality);
  2558.  
  2559. }
  2560.  
  2561. document.documentElement.classList.remove("video_unstarted", "video_active", "video_ended", "video_playing", "video_paused", "video_buffering", "video_cued");
  2562.  
  2563. switch (event) {
  2564.  
  2565. case -1:
  2566. document.documentElement.classList.add("video_unstarted");
  2567. break;
  2568. case 0:
  2569. document.documentElement.classList.add("video_ended");
  2570. break;
  2571. case 1:
  2572. document.documentElement.classList.add("video_active", "video_playing");
  2573. break;
  2574. case 2:
  2575. document.documentElement.classList.add("video_active", "video_paused");
  2576. break;
  2577. case 3:
  2578. document.documentElement.classList.add("video_active", "video_buffering");
  2579. break;
  2580. case 5:
  2581. document.documentElement.classList.add("video_cued");
  2582. break;
  2583.  
  2584. }
  2585.  
  2586. window.dispatchEvent(new Event("resize"));
  2587.  
  2588. },
  2589. playerReady: function (api) {
  2590.  
  2591. var timestamp;
  2592. var handleCustomsListener;
  2593.  
  2594. if (api) {
  2595.  
  2596. handleCustomsListener = this.handleCustoms.bind(this);
  2597.  
  2598. api.addEventListener("SIZE_CLICKED", handleCustomsListener);
  2599. api.addEventListener("onVolumeChange", handleCustomsListener);
  2600. api.addEventListener("onStateChange", this.onStateChange.bind(this));
  2601.  
  2602. if (user_settings.player_memorize_volume) {
  2603.  
  2604. api.setVolume(user_settings.userVolume);
  2605.  
  2606. timestamp = Date.now();
  2607.  
  2608. iridium_api.setStorage(
  2609. "yt-player-volume",
  2610. JSON.stringify({
  2611. data: JSON.stringify({
  2612. volume: user_settings.userVolume,
  2613. muted: false
  2614. }),
  2615. creation: timestamp,
  2616. expiration: timestamp + 2592E6
  2617. })
  2618. );
  2619.  
  2620. }
  2621.  
  2622. }
  2623.  
  2624. },
  2625. shareApi: function (original) {
  2626.  
  2627. var context = this;
  2628.  
  2629. return function (api) {
  2630.  
  2631. context.playerReady(api);
  2632.  
  2633. var ytSignalInstance;
  2634.  
  2635. ytSignalInstance = window["ytSignalsInstance"];
  2636.  
  2637. if (!ytSignalInstance) {
  2638. if (ytSignalInstance = window["ytSignals"]) {
  2639. ytSignalInstance = ytSignalInstance["getInstance"] && ytSignalInstance["getInstance"]();
  2640. }
  2641. }
  2642.  
  2643. if (ytSignalInstance && ytSignalInstance["processSignal"]) {
  2644. ytSignalInstance["processSignal"]("eocs");
  2645. // ytSignalInstance["processSignal"]("fwtr"); // first warm transition requested
  2646. }
  2647.  
  2648. if (original) {
  2649. return original.apply(this, arguments);
  2650. }
  2651.  
  2652. };
  2653. },
  2654. isChannel: function () {
  2655. return /^\/(user|channel)\//.test(window.location.pathname);
  2656. },
  2657. loadStart: function (event) {
  2658.  
  2659. var is_watch;
  2660. var is_playlist;
  2661. var yt_player_manager;
  2662.  
  2663. if (event) {
  2664.  
  2665. is_watch = window.location.pathname === "/watch";
  2666. is_playlist = !!window.location.search.match(/list=[A-Z]{2}/);
  2667.  
  2668. switch (event.type) {
  2669.  
  2670. case "popstate":
  2671. case "yt-navigate-start":
  2672.  
  2673. if (!user_settings.player_auto_play) {
  2674. if (is_watch && this.previous_url !== window.location.href && (is_watch !== this.was_watch || is_playlist !== this.was_playlist)) {
  2675. if ((yt_player_manager = document.querySelector("yt-player-manager")) && yt_player_manager["playerContainer_"]) {
  2676. yt_player_manager["playerContainer_"] = undefined;
  2677. }
  2678. }
  2679. }
  2680.  
  2681. break;
  2682.  
  2683. }
  2684.  
  2685. this.previous_url = is_watch ? window.location.href : this.previous_url;
  2686. this.was_watch = is_watch;
  2687. this.was_playlist = is_playlist;
  2688.  
  2689. }
  2690.  
  2691. },
  2692. ini: function () {
  2693.  
  2694. var context;
  2695. var timestamp;
  2696.  
  2697. if (iridium_api.initializeOption.call(this)) {
  2698. return;
  2699. }
  2700.  
  2701. if (user_settings.player_quality !== "auto") {
  2702.  
  2703. timestamp = Date.now();
  2704.  
  2705. iridium_api.setStorage(
  2706. "yt-player-quality",
  2707. JSON.stringify({
  2708. data: user_settings.player_quality,
  2709. creation: timestamp,
  2710. expiration: timestamp + 2592E6
  2711. })
  2712. );
  2713.  
  2714. }
  2715.  
  2716. if (this.loadStartListener) {
  2717.  
  2718. window.removeEventListener("yt-page-data-updated", this.loadStartListener, true);
  2719. window.removeEventListener("yt-navigate-start", this.loadStartListener, false);
  2720. window.removeEventListener("yt-navigate-finish", this.loadStartListener, false);
  2721. window.removeEventListener("popstate", this.loadStartListener, true);
  2722.  
  2723. }
  2724.  
  2725. if (this.setPlayerResizeListener) {
  2726. window.removeEventListener("yt-navigate-finish", this.setPlayerResizeListener, false);
  2727. }
  2728.  
  2729. if (this.fileLoadListener) {
  2730. document.documentElement.removeEventListener("load", this.fileLoadListener, true);
  2731. }
  2732.  
  2733. this.loadStartListener = this.loadStart.bind(this);
  2734. this.setPlayerResizeListener = this.setPlayerResize.bind(this);
  2735. this.fileLoadListener = this.interceptHooks.bind(this);
  2736.  
  2737. window.addEventListener("yt-page-data-updated", this.loadStartListener, true);
  2738. window.addEventListener("yt-navigate-start", this.loadStartListener, false);
  2739. window.addEventListener("yt-navigate-finish", this.loadStartListener, false);
  2740. window.addEventListener("popstate", this.loadStartListener, true);
  2741. window.addEventListener("yt-navigate-finish", this.setPlayerResizeListener, false);
  2742.  
  2743. document.documentElement.addEventListener("load", this.fileLoadListener, true);
  2744.  
  2745. window.onYouTubePlayerReady = this.shareApi(window.onYouTubePlayerReady);
  2746. JSON.parse = this.modJSONParse(JSON.parse);
  2747. XMLHttpRequest.prototype.open = this.modOpen(XMLHttpRequest.prototype.open);
  2748. DOMParser.prototype.parseFromString = this.modParseFromString(DOMParser.prototype.parseFromString);
  2749.  
  2750. this.interceptHooks();
  2751.  
  2752. context = this;
  2753.  
  2754. Object.defineProperties(Object.prototype, {
  2755. cueVideoByPlayerVars: {
  2756. set: function (data) {
  2757. this._cueVideoByPlayerVars = data;
  2758. },
  2759. get: function () {
  2760. return context.modVideoByPlayerVars(this._cueVideoByPlayerVars);
  2761. }
  2762. },
  2763. loadVideoByPlayerVars: {
  2764. set: function (data) {
  2765. this._loadVideoByPlayerVars = data;
  2766. },
  2767. get: function () {
  2768.  
  2769. if (context.isChannel() ? !user_settings.channel_trailer_auto_play : !user_settings.player_auto_play) {
  2770. return this.cueVideoByPlayerVars;
  2771. }
  2772.  
  2773. return context.modVideoByPlayerVars(this._loadVideoByPlayerVars);
  2774.  
  2775. }
  2776. },
  2777. playVideo: {
  2778. set: function (data) {
  2779. this._playVideo = data;
  2780. },
  2781. get: function () {
  2782.  
  2783. if (context.isChannel() ? !user_settings.channel_trailer_auto_play : !user_settings.player_auto_play) {
  2784. if (!document.querySelector(".ad-showing,.ad-interrupting")) {
  2785. return function () {
  2786. };
  2787. }
  2788. }
  2789.  
  2790. return this._playVideo;
  2791.  
  2792. }
  2793. },
  2794. experiments: {
  2795. set: function (data) {
  2796. this._experiments = data;
  2797. },
  2798. get: function experimentsGetter() {
  2799.  
  2800. var i;
  2801. var matching;
  2802. var keys_list;
  2803. var function_string;
  2804.  
  2805. keys_list = Object.keys(this);
  2806.  
  2807. for (i = 0; i < keys_list.length; i++) {
  2808. if (this[keys_list[i]] && this[keys_list[i]]["innertubeApiKey"]) {
  2809.  
  2810. if (this["playerStyle"] && (context.isChannel() ? !user_settings.channel_trailer_auto_play : !user_settings.player_auto_play)) {
  2811.  
  2812. function_string = experimentsGetter["caller"].toString();
  2813. matching = function_string.match(/this\.([a-z0-9$_]{1,3})=[^;]+\.autoplayoverride/i);
  2814.  
  2815. if (matching && matching[1]) {
  2816. this[matching[1]] = false;
  2817. }
  2818.  
  2819. }
  2820.  
  2821. break;
  2822.  
  2823. }
  2824. }
  2825.  
  2826. return this._experiments;
  2827.  
  2828. }
  2829. }
  2830. });
  2831.  
  2832. }
  2833. },
  2834. {
  2835. options: {
  2836. player_quick_controls: {
  2837. id: "player_quick_controls",
  2838. section: "video",
  2839. sub_section: "general",
  2840. type: "checkbox",
  2841. value: true,
  2842. i18n: {
  2843. label: "Enable quick controls",
  2844. button_auto_play: "Autoplay",
  2845. button_pop_up_player: "Pop-up Video",
  2846. button_full_browser: "Full Browser",
  2847. button_screen_shot: "Screen Shot",
  2848. button_thumbnails: "Thumbnails",
  2849. thumbnails_title: "Click to download\nRight click for options",
  2850. screen_shot_title: "Right click for options",
  2851. full_browser_info: "Click here or\npress \"Esc\" to exit"
  2852. }
  2853. }
  2854. },
  2855. exitFullBrowser: function (event) {
  2856.  
  2857. var video_player;
  2858.  
  2859. if (!user_settings.fullBrowser || (event.type === "click" || event.keyCode === 27 || event.key === "Escape")) {
  2860.  
  2861. window.removeEventListener("keydown", this.exitFullBrowserlistener, false);
  2862. this.exitFullBrowserlistener = null;
  2863. document.documentElement.classList.remove("iri-full-browser");
  2864. user_settings.fullBrowser = false;
  2865. iridium_api.saveSettings("fullBrowser");
  2866. window.dispatchEvent(new Event("resize"));
  2867.  
  2868. if (video_player = document.getElementById("movie_player")) {
  2869. if (!document.querySelector("[theater]")) {
  2870. video_player.setSizeStyle(true, false);
  2871. }
  2872. }
  2873.  
  2874. this.quickControlsState();
  2875.  
  2876. }
  2877.  
  2878. },
  2879. quickControlAutoPlay: function () {
  2880.  
  2881. user_settings.player_auto_play = !user_settings.player_auto_play;
  2882. iridium_api.saveSettings("player_auto_play");
  2883. this.quickControlsState();
  2884.  
  2885. },
  2886. closeThumbnails: function (event) {
  2887.  
  2888. var thumbnail_gallery;
  2889.  
  2890. if (event.target.tagName !== "IMG" && (thumbnail_gallery = document.getElementById("iri-thumbnail-gallery"))) {
  2891. thumbnail_gallery.remove();
  2892. }
  2893.  
  2894. },
  2895. closeScreenShot: function (event) {
  2896.  
  2897. var link;
  2898. var screen_shot_container;
  2899.  
  2900. if (event.target.tagName !== "CANVAS" && (screen_shot_container = document.getElementById("iri-screen-shot-container"))) {
  2901.  
  2902. if (link = screen_shot_container.querySelector("a")) {
  2903. URL.revokeObjectURL(link.href);
  2904. }
  2905.  
  2906. screen_shot_container.remove();
  2907.  
  2908. }
  2909.  
  2910. },
  2911. quickControlThumbnail: function () {
  2912.  
  2913. var i;
  2914. var video_id;
  2915. var thumbnail_list;
  2916. var thumbnail_base;
  2917. var thumbnail_size;
  2918. var thumbnail_gallery;
  2919. var thumbnail_size_list;
  2920.  
  2921. if (video_id = window.location.href.match(iridium_api.videoIdPattern)) {
  2922.  
  2923. thumbnail_base = window.location.protocol + "//i.ytimg.com/vi/";
  2924.  
  2925. thumbnail_size_list = {
  2926. iurl: "default.jpg",
  2927. iurlmq: "mqdefault.jpg",
  2928. iurlhq: "hqdefault.jpg",
  2929. iurlsd: "sddefault.jpg",
  2930. iurlhq720: "hq720.jpg",
  2931. iurlmaxres: "maxresdefault.jpg"
  2932. };
  2933.  
  2934. thumbnail_gallery = document.createElement("template");
  2935. thumbnail_gallery.innerHTML =
  2936. "<div id='iri-thumbnail-gallery'>" +
  2937. " <div id='iri-thumbnail-gallery-first-row'>" +
  2938. " <div class='iri-thumbnail-labels'>" +
  2939. " <div>MAXRES</div>" +
  2940. " <div>HQ720</div>" +
  2941. " <div>SD</div>" +
  2942. " </div>" +
  2943. " <a target='_blank' download>" +
  2944. " <img data-thumbnail-type='iurlmaxres' />" +
  2945. " </a>" +
  2946. " <a target='_blank' download>" +
  2947. " <img data-thumbnail-type='iurlhq720' />" +
  2948. " </a>" +
  2949. " <a target='_blank' download>" +
  2950. " <img data-thumbnail-type='iurlsd' />" +
  2951. " </a>" +
  2952. " </div>" +
  2953. " <div id='iri-thumbnail-gallery-second-row'>" +
  2954. " <div class='iri-thumbnail-labels'>" +
  2955. " <div>HQ</div>" +
  2956. " <div>MQ</div>" +
  2957. " <div>DEFAULT</div>" +
  2958. " </div>" +
  2959. " <a target='_blank' download>" +
  2960. " <img data-thumbnail-type='iurlhq' />" +
  2961. " </a>" +
  2962. " <a target='_blank' download>" +
  2963. " <img data-thumbnail-type='iurlmq' />" +
  2964. " </a>" +
  2965. " <a target='_blank' download>" +
  2966. " <img data-thumbnail-type='iurl' />" +
  2967. " </a>" +
  2968. " </div>" +
  2969. "</div>";
  2970. thumbnail_gallery = thumbnail_gallery.content;
  2971.  
  2972. thumbnail_list = thumbnail_gallery.querySelectorAll("[data-thumbnail-type]");
  2973.  
  2974. for (i = 0; i < thumbnail_list.length; i++) {
  2975.  
  2976. thumbnail_size = thumbnail_list[i].dataset.thumbnailType;
  2977.  
  2978. if (thumbnail_size = thumbnail_size_list[thumbnail_size]) {
  2979.  
  2980. thumbnail_list[i].src = thumbnail_base + video_id[1] + "/" + thumbnail_size;
  2981. thumbnail_list[i].parentNode.href = thumbnail_list[i].src;
  2982. thumbnail_list[i].parentNode.title = i18n.player_quick_controls.thumbnails_title;
  2983.  
  2984. }
  2985.  
  2986. }
  2987.  
  2988. thumbnail_gallery.firstChild.addEventListener("click", this.closeThumbnails.bind(this), false);
  2989.  
  2990. document.documentElement.appendChild(thumbnail_gallery);
  2991.  
  2992. }
  2993.  
  2994. },
  2995. quickControlFullBrowser: function (event) {
  2996.  
  2997. var video_player;
  2998. var full_browser_info;
  2999.  
  3000. if (this.exitFullBrowserlistener) {
  3001.  
  3002. window.removeEventListener("keydown", this.exitFullBrowserlistener, false);
  3003. this.exitFullBrowserlistener = null;
  3004.  
  3005. }
  3006.  
  3007. if (event) {
  3008.  
  3009. user_settings.fullBrowser = !user_settings.fullBrowser;
  3010. iridium_api.saveSettings("fullBrowser");
  3011.  
  3012. }
  3013.  
  3014. if (user_settings.fullBrowser) {
  3015.  
  3016. document.documentElement.classList.add("iri-full-browser");
  3017. document.documentElement.scrollTop = 0;
  3018.  
  3019. if (video_player = document.getElementById("movie_player")) {
  3020.  
  3021. this.exitFullBrowserlistener = this.exitFullBrowser.bind(this);
  3022. window.addEventListener("keydown", this.exitFullBrowserlistener, false);
  3023. window.dispatchEvent(new Event("resize"));
  3024.  
  3025. if (!document.getElementById("iri-full-browser-info")) {
  3026.  
  3027. full_browser_info = document.createElement("template");
  3028. full_browser_info.innerHTML =
  3029. "<div id='iri-full-browser-info'>" +
  3030. " <div id='iri-full-browser-info-message' data-locale='text|full_browser_info'></div>" +
  3031. "</div>";
  3032. full_browser_info = full_browser_info.content;
  3033.  
  3034. iridium_api.applyText(full_browser_info, i18n.player_quick_controls);
  3035. video_player.insertBefore(full_browser_info.firstChild, video_player.firstChild);
  3036. video_player.querySelector("#iri-full-browser-info-message").addEventListener("click", this.exitFullBrowserlistener, false);
  3037.  
  3038. }
  3039.  
  3040. }
  3041.  
  3042. } else if (!user_settings.fullBrowser && document.documentElement.classList.contains("iri-full-browser")) {
  3043.  
  3044. document.documentElement.classList.remove("iri-full-browser");
  3045. window.dispatchEvent(new Event("resize"));
  3046.  
  3047. }
  3048.  
  3049. if (event) {
  3050. this.quickControlsState();
  3051. }
  3052.  
  3053. },
  3054. quickControlScreenShot: function () {
  3055.  
  3056. var canvas;
  3057. var aspect_ratio;
  3058. var video;
  3059. var canvas_height;
  3060. var canvas_width;
  3061. var canvas_context;
  3062. var screen_shot_container;
  3063.  
  3064. if ((video = document.querySelector("video")) && video.src) {
  3065.  
  3066. if (!(screen_shot_container = document.getElementById("iri-screen-shot-container"))) {
  3067.  
  3068. screen_shot_container = document.createElement("template");
  3069. screen_shot_container.innerHTML =
  3070. "<div id='iri-screen-shot-container'>" +
  3071. " <a target='_blank' download data-locale='title|screen_shot_title'>" +
  3072. " <canvas></canvas>" +
  3073. " </a>" +
  3074. "</div>";
  3075. screen_shot_container = screen_shot_container.content;
  3076.  
  3077. }
  3078.  
  3079. iridium_api.applyText(screen_shot_container, i18n.player_quick_controls);
  3080.  
  3081. canvas = screen_shot_container.querySelector("canvas");
  3082. canvas_context = canvas.getContext("2d");
  3083. aspect_ratio = video.videoWidth / video.videoHeight;
  3084. canvas_width = video.videoWidth;
  3085. canvas_height = parseInt(canvas_width / aspect_ratio, 10);
  3086. canvas.width = canvas_width;
  3087. canvas.height = canvas_height;
  3088. canvas_context.drawImage(video, 0, 0, canvas_width, canvas_height);
  3089.  
  3090. canvas.toBlob(function (blob) {
  3091.  
  3092. canvas.parentNode.href = URL.createObjectURL(blob);
  3093.  
  3094. });
  3095.  
  3096. screen_shot_container.firstChild.addEventListener("click", this.closeScreenShot.bind(this), false);
  3097.  
  3098. document.documentElement.appendChild(screen_shot_container);
  3099.  
  3100. }
  3101.  
  3102. },
  3103. quickControlPopUpPlayer: function (event) {
  3104.  
  3105. window.postMessage({
  3106. id: user_settings.broadcast_id,
  3107. action: "ini-pop-up-player",
  3108. screenX: event.screenX,
  3109. screenY: event.screenY
  3110. }, "*");
  3111.  
  3112. },
  3113. quickControls: function (event) {
  3114.  
  3115. switch (event.target.id) {
  3116.  
  3117. case "iri-quick-control-auto-play":
  3118. this.quickControlAutoPlay();
  3119. break;
  3120.  
  3121. case "iri-quick-control-thumbnail":
  3122. this.quickControlThumbnail();
  3123. break;
  3124.  
  3125. case "iri-quick-control-full-browser":
  3126. this.quickControlFullBrowser(event);
  3127. break;
  3128.  
  3129. case "iri-quick-control-screen-shot":
  3130. this.quickControlScreenShot(event);
  3131. break;
  3132.  
  3133. case "iri-quick-control-pop-up-player":
  3134. this.quickControlPopUpPlayer(event);
  3135. break;
  3136.  
  3137. }
  3138.  
  3139. },
  3140. quickControlsState: function () {
  3141.  
  3142. var button;
  3143.  
  3144. if (button = document.getElementById("iri-quick-control-auto-play")) {
  3145.  
  3146. if (user_settings.player_auto_play) {
  3147. button.setAttribute("enabled", "true");
  3148. } else {
  3149. button.removeAttribute("enabled");
  3150. }
  3151.  
  3152. }
  3153.  
  3154. if (button = document.getElementById("iri-quick-control-full-browser")) {
  3155.  
  3156. if (user_settings.fullBrowser) {
  3157.  
  3158. button.setAttribute("enabled", "true");
  3159. this.quickControlFullBrowser();
  3160.  
  3161. } else {
  3162.  
  3163. button.removeAttribute("enabled");
  3164. this.quickControlFullBrowser();
  3165.  
  3166. }
  3167.  
  3168. }
  3169.  
  3170. },
  3171. loadStart: function (event) {
  3172.  
  3173. var controls;
  3174. var meta_section;
  3175.  
  3176. if (this.quickControlsListener) {
  3177.  
  3178. document.removeEventListener("click", this.quickControlsListener, false);
  3179. this.quickControlsListener = null;
  3180.  
  3181. }
  3182.  
  3183. controls = document.querySelector("#iri-quick-controls");
  3184.  
  3185. if (user_settings.player_quick_controls && document.querySelector("ytd-watch:not([hidden]), ytd-watch-flexy:not([hidden])") && (meta_section = document.querySelector("#menu-container"))) {
  3186.  
  3187. if (!controls) {
  3188.  
  3189. controls = document.createElement("template");
  3190. controls.innerHTML =
  3191. "<div id='iri-quick-controls' class='closed-mode'>" +
  3192. " <div id='iri-quick-controls-container'>" +
  3193. " <button id='iri-quick-control-auto-play'>" +
  3194. " <svg viewBox='0 0 20 20' height='20' width='20'>" +
  3195. " <polygon points='3 2 16.9 10 3 18'/>" +
  3196. " </svg>" +
  3197. " <div class='iri-quick-controls-tooltip' data-locale='text|button_auto_play'></div>" +
  3198. " </button>" +
  3199. " <button id='iri-quick-control-full-browser'>" +
  3200. " <svg viewBox='0 0 20 20' height='20' width='20'>" +
  3201. " <path d='M0 4v12h20V4H0z M12 12H2V6h10V12'/>" +
  3202. " </svg>" +
  3203. " <div class='iri-quick-controls-tooltip' data-locale='text|button_full_browser'></div>" +
  3204. " </button>" +
  3205. " <button id='iri-quick-control-screen-shot'>" +
  3206. " <svg viewBox='0 0 20 20' height='20' width='20'>" +
  3207. " <circle cx='13' cy='10' r='3.5'/>" +
  3208. " <path d='M0 4v12h20V4H0z M7 7H1V5h6V7z M13 15c-2.8 0-5-2.2-5-5s2.2-5 5-5s5 2.2 5 5S15.8 15 13 15z'/>" +
  3209. " </svg>" +
  3210. " <div class='iri-quick-controls-tooltip' data-locale='text|button_screen_shot'></div>" +
  3211. " </button>" +
  3212. " <button id='iri-quick-control-thumbnail'>" +
  3213. " <svg viewBox='0 0 20 20' height='20' width='20'>" +
  3214. " <circle cx='8' cy='7.2' r='2'/>" +
  3215. " <path d='M0 2v16h20V2H0z M18 16H2V4h16V16z'/>" +
  3216. " <polygon points='17 10.9 14 7.9 9 12.9 6 9.9 3 12.9 3 15 17 15'/>" +
  3217. " </svg>" +
  3218. " <div class='iri-quick-controls-tooltip' data-locale='text|button_thumbnails'></div>" +
  3219. " </button>" +
  3220. " <button id='iri-quick-control-pop-up-player'>" +
  3221. " <svg viewBox='0 0 20 20' height='20' width='20'>" +
  3222. " <path d='M18 2H6v4H2v12h12v-4h4V2z M12 16H4V8h2v6h6V16z M16 12h-2h-2H8V8V6V4h8V12z'/>" +
  3223. " </svg>" +
  3224. " <div class='iri-quick-controls-tooltip' data-locale='text|button_pop_up_player'></div>" +
  3225. " </button>" +
  3226. " </div>" +
  3227. "</div>";
  3228. controls = controls.content;
  3229.  
  3230. iridium_api.applyText(controls, i18n.player_quick_controls);
  3231. meta_section.parentNode.insertBefore(controls, meta_section);
  3232.  
  3233. }
  3234.  
  3235. this.quickControlsState();
  3236.  
  3237. this.quickControlsListener = this.quickControls.bind(this);
  3238.  
  3239. document.addEventListener("click", this.quickControlsListener, false);
  3240.  
  3241. } else if (controls && !user_settings.player_quick_controls) {
  3242. controls.remove();
  3243. }
  3244.  
  3245. },
  3246. onSettingsUpdated: function () {
  3247. this.quickControlsState();
  3248. },
  3249. ini: function () {
  3250.  
  3251. if (iridium_api.initializeOption.call(this)) {
  3252. return;
  3253. }
  3254.  
  3255. if (this.loadStartListener) {
  3256.  
  3257. window.removeEventListener("yt-page-data-updated", this.loadStartListener, true);
  3258. window.removeEventListener("yt-navigate-start", this.loadStartListener, false);
  3259. window.removeEventListener("yt-navigate-finish", this.loadStartListener, false);
  3260. window.removeEventListener("popstate", this.loadStartListener, true);
  3261.  
  3262. }
  3263.  
  3264. this.loadStartListener = this.loadStart.bind(this);
  3265.  
  3266. window.addEventListener("yt-page-data-updated", this.loadStartListener, true);
  3267. window.addEventListener("yt-navigate-start", this.loadStartListener, false);
  3268. window.addEventListener("yt-navigate-finish", this.loadStartListener, false);
  3269. window.addEventListener("popstate", this.loadStartListener, true);
  3270.  
  3271. }
  3272. },
  3273. {
  3274. options: {
  3275. comments_visibility: {
  3276. id: "comments_visibility",
  3277. section: "video",
  3278. sub_section: "general",
  3279. type: "dropdown",
  3280. value: 1,
  3281. i18n: {
  3282. label: "Comment section:",
  3283. button_show_comments: "Show comments",
  3284. options: [
  3285. "Show",
  3286. "Hide",
  3287. "Remove"
  3288. ]
  3289. },
  3290. options: [
  3291. 0,
  3292. 1,
  3293. 2
  3294. ]
  3295. }
  3296. },
  3297. modOnShow: function (original) {
  3298.  
  3299. return function (bypass) {
  3300.  
  3301. var comments_loaded;
  3302. var comment_contents;
  3303.  
  3304. if (window.location.pathname !== "/watch") {
  3305. return original.apply(this, arguments);
  3306. }
  3307.  
  3308. if (user_settings.comments_visibility > 1) {
  3309. return function () {
  3310. };
  3311. }
  3312.  
  3313. comments_loaded = (comment_contents = document.querySelector("ytd-comments #contents")) && !!comment_contents.firstElementChild;
  3314.  
  3315. if (bypass || comments_loaded || user_settings.comments_visibility < 1) {
  3316. return original.apply(this, arguments);
  3317. }
  3318.  
  3319. return function () {
  3320. };
  3321.  
  3322. };
  3323.  
  3324. },
  3325. iniLoadComments: function (event) {
  3326.  
  3327. var comment_section = document.querySelector("ytd-comments yt-next-continuation");
  3328.  
  3329. event.target.remove();
  3330.  
  3331. if (comment_section) {
  3332. comment_section.onShow(true);
  3333. }
  3334.  
  3335. },
  3336. iniLoadCommentsButton: function () {
  3337.  
  3338. var button;
  3339. var comment_section;
  3340.  
  3341. button = document.getElementById("iri-show-comments");
  3342.  
  3343. if (!button && (comment_section = document.querySelector("ytd-comments"))) {
  3344.  
  3345. button = document.createElement("div");
  3346. button.id = "iri-show-comments";
  3347. button.textContent = i18n.comments_visibility.button_show_comments;
  3348. button.addEventListener("click", this.iniLoadComments.bind(this), false);
  3349.  
  3350. comment_section.insertBefore(button, comment_section.firstChild);
  3351.  
  3352. }
  3353.  
  3354. },
  3355. iniLoadStartListener: function () {
  3356.  
  3357. var button;
  3358. var comment_section;
  3359. var comment_contents;
  3360.  
  3361. if (user_settings.comments_visibility > 0) {
  3362.  
  3363. if (!((comment_contents = document.querySelector("ytd-comments #contents")) && comment_contents.firstElementChild)) {
  3364. if (comment_section = document.querySelector("ytd-comments yt-next-continuation")) {
  3365.  
  3366. if (comment_section.onShow) {
  3367. comment_section.onShow = this.modOnShow(comment_section.onShow);
  3368. }
  3369.  
  3370. if (user_settings.comments_visibility < 2) {
  3371. this.iniLoadCommentsButton();
  3372. }
  3373. }
  3374.  
  3375. } else if (comment_contents.firstElementChild && (button = document.getElementById("iri-show-comments"))) {
  3376. button.remove();
  3377. }
  3378.  
  3379. }
  3380.  
  3381. },
  3382. ini: function () {
  3383.  
  3384. if (iridium_api.initializeOption.call(this)) {
  3385. return;
  3386. }
  3387.  
  3388. window.addEventListener("yt-visibility-refresh", this.iniLoadStartListener.bind(this), true);
  3389.  
  3390. }
  3391. },
  3392. {
  3393. options: {
  3394. shortcuts_always_active: {
  3395. id: "shortcuts_always_active",
  3396. section: "video",
  3397. sub_section: "player",
  3398. type: "checkbox",
  3399. value: true,
  3400. i18n: {
  3401. label: "Player shortcuts always active"
  3402. }
  3403. }
  3404. },
  3405. alwaysActive: function (event) {
  3406.  
  3407. var i;
  3408. var api;
  3409. var list;
  3410. var clear;
  3411. var length;
  3412. var event_clone;
  3413.  
  3414. if (!user_settings.shortcuts_always_active) {
  3415. return;
  3416. }
  3417.  
  3418. if (api = document.getElementById("movie_player")) {
  3419.  
  3420. clear = window.location.pathname === "/watch" && api && api !== event.target && !api.contains(event.target);
  3421.  
  3422. clear = clear && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey && !event.target.isContentEditable;
  3423.  
  3424. clear = clear && (event.which > 47 && event.which < 58 || event.which > 95 && event.which < 106 || [27, 32, 35, 36, 37, 38, 39, 40, 66, 67, 79, 87, 187, 189].indexOf(event.which) > -1);
  3425.  
  3426. if (clear && ["EMBED", "INPUT", "OBJECT", "TEXTAREA", "IFRAME"].indexOf(document.activeElement.tagName) === -1) {
  3427.  
  3428. event_clone = new Event("keydown");
  3429. list = Object.keys(Object.getPrototypeOf(event));
  3430. length = list.length;
  3431.  
  3432. for (i = 0; i < length; i++) {
  3433. event_clone[list[i]] = event[list[i]];
  3434. }
  3435.  
  3436. event.preventDefault();
  3437. api.dispatchEvent(event_clone);
  3438.  
  3439. }
  3440.  
  3441. }
  3442.  
  3443. },
  3444. ini: function () {
  3445.  
  3446. if (iridium_api.initializeOption.call(this)) {
  3447. return;
  3448. }
  3449.  
  3450. document.addEventListener("keydown", this.alwaysActive.bind(this), false);
  3451.  
  3452. }
  3453. },
  3454. {
  3455. options: {
  3456. player_volume_wheel: {
  3457. id: "player_volume_wheel",
  3458. section: "video",
  3459. sub_section: "player",
  3460. type: "checkbox",
  3461. value: false,
  3462. i18n: {
  3463. label: "Change volume using the mouse wheel"
  3464. }
  3465. }
  3466. },
  3467. changeVolume: function (event) {
  3468.  
  3469. var api;
  3470. var player;
  3471. var direction;
  3472. var timestamp;
  3473. var can_scroll;
  3474. var new_volume;
  3475. var player_state;
  3476. var chrome_bottom;
  3477. var invideo_drawer;
  3478. var player_settings;
  3479. var fullscreen_playlist;
  3480.  
  3481. if (!user_settings.player_volume_wheel) {
  3482. return;
  3483. }
  3484.  
  3485. api = document.getElementById("movie_player");
  3486. player = document.querySelector("video");
  3487. invideo_drawer = document.querySelector(".iv-drawer");
  3488. player_settings = document.querySelector(".ytp-settings-menu");
  3489. fullscreen_playlist = document.querySelector(".ytp-playlist-menu");
  3490. can_scroll = (!fullscreen_playlist || !fullscreen_playlist.contains(event.target)) && (!invideo_drawer || !invideo_drawer.contains(event.target)) && (!player_settings || !player_settings.contains(event.target));
  3491.  
  3492. if (can_scroll && player && api && api.contains(event.target)) {
  3493.  
  3494. player_state = api.getPlayerState();
  3495.  
  3496. if (player_state > 0 && player_state < 5) {
  3497.  
  3498. event.preventDefault();
  3499. chrome_bottom = document.querySelector(".ytp-chrome-bottom");
  3500.  
  3501. if (chrome_bottom) {
  3502.  
  3503. if (!chrome_bottom.classList.contains("ytp-volume-slider-active")) {
  3504. chrome_bottom.classList.add("ytp-volume-slider-active");
  3505. }
  3506.  
  3507. if (chrome_bottom.timer) {
  3508. window.clearTimeout(chrome_bottom.timer);
  3509. }
  3510.  
  3511. api.dispatchEvent(new Event("mousemove"));
  3512.  
  3513. chrome_bottom.timer = window.setTimeout(function () {
  3514. if (chrome_bottom && chrome_bottom.classList.contains("ytp-volume-slider-active")) {
  3515.  
  3516. chrome_bottom.classList.remove("ytp-volume-slider-active");
  3517. delete chrome_bottom.timer;
  3518.  
  3519. }
  3520. }, 4000);
  3521.  
  3522. }
  3523.  
  3524. direction = event.deltaY || event.wheelDeltaY;
  3525. new_volume = api.getVolume() - (Math.sign(direction) * 5);
  3526.  
  3527. if (new_volume < 0) {
  3528. new_volume = 0;
  3529. } else if (new_volume > 100) {
  3530. new_volume = 100;
  3531. }
  3532.  
  3533. api.setVolume(new_volume);
  3534.  
  3535. timestamp = Date.now();
  3536.  
  3537. iridium_api.setStorage(
  3538. "yt-player-volume",
  3539. JSON.stringify({
  3540. data: JSON.stringify({
  3541. volume: new_volume,
  3542. muted: false
  3543. }),
  3544. creation: timestamp,
  3545. expiration: timestamp + 2592E6
  3546. })
  3547. );
  3548.  
  3549. return false;
  3550.  
  3551. }
  3552.  
  3553. }
  3554.  
  3555. },
  3556. ini: function () {
  3557.  
  3558. if (iridium_api.initializeOption.call(this)) {
  3559. return;
  3560. }
  3561.  
  3562. document.addEventListener("wheel", this.changeVolume.bind(this));
  3563.  
  3564. }
  3565. },
  3566. {
  3567. options: {
  3568. player_always_visible: {
  3569. id: "player_always_visible",
  3570. section: "video",
  3571. sub_section: "player",
  3572. type: "checkbox",
  3573. value: true,
  3574. i18n: {
  3575. label: "Video stays always visible while scrolling"
  3576. }
  3577. }
  3578. },
  3579. move_data: {
  3580. is_mini: false,
  3581. mouse_offset: {X: 0, Y: 0},
  3582. player_position: {X: 0, Y: 0, snapRight: true, snapBottom: true},
  3583. player_dimension: {height: 0, width: 0}
  3584. },
  3585. updatePlayerPosition: function (is_moving) {
  3586.  
  3587. var style;
  3588. var masthead;
  3589. var video_player;
  3590. var player_margin;
  3591. var style_element;
  3592. var masthead_offset;
  3593.  
  3594. is_moving = is_moving === true;
  3595. player_margin = 10;
  3596. masthead_offset = player_margin;
  3597.  
  3598. if (!this.move_data.is_mini || document.webkitIsFullScreen || window.fullScreen) {
  3599. return;
  3600. }
  3601.  
  3602. if (masthead = document.getElementById("masthead")) {
  3603. masthead_offset += masthead.offsetHeight;
  3604. }
  3605.  
  3606. this.move_data.player_position.snapRight = false;
  3607. this.move_data.player_position.snapBottom = false;
  3608.  
  3609. if (is_moving || !user_settings.miniPlayer.position.snapRight) {
  3610.  
  3611. if (this.move_data.player_position.X < player_margin) {
  3612. this.move_data.player_position.X = player_margin;
  3613. } else if (this.move_data.player_position.X + this.move_data.player_dimension.width > document.documentElement.clientWidth - player_margin) {
  3614. this.move_data.player_position.snapRight = true;
  3615. }
  3616.  
  3617. }
  3618.  
  3619. if (is_moving || !user_settings.miniPlayer.position.snapBottom) {
  3620.  
  3621. if (this.move_data.player_position.Y < masthead_offset) {
  3622. this.move_data.player_position.Y = masthead_offset;
  3623. } else if (this.move_data.player_position.Y + this.move_data.player_dimension.height > document.documentElement.clientHeight - player_margin) {
  3624. this.move_data.player_position.snapBottom = true;
  3625. }
  3626.  
  3627. }
  3628.  
  3629. if (video_player = document.getElementById("movie_player")) {
  3630.  
  3631. style = "";
  3632.  
  3633. if (!is_moving && user_settings.miniPlayer.position.snapRight || this.move_data.player_position.snapRight) {
  3634. style += "right:" + player_margin + "px;";
  3635. } else {
  3636. style += "left:" + this.move_data.player_position.X + "px;";
  3637. }
  3638.  
  3639. if (!is_moving && user_settings.miniPlayer.position.snapBottom || this.move_data.player_position.snapBottom) {
  3640. style += "bottom:" + player_margin + "px;";
  3641. } else {
  3642. style += "top:" + this.move_data.player_position.Y + "px;";
  3643. }
  3644.  
  3645. if (!(style_element = document.getElementById("style-mini-player"))) {
  3646.  
  3647. style_element = document.createElement("style");
  3648. style_element.id = "style-mini-player";
  3649.  
  3650. video_player.parentNode.insertBefore(style_element, video_player);
  3651.  
  3652. }
  3653.  
  3654. style_element.textContent =
  3655. ".iri-always-visible:not(.iri-full-browser) #movie_player:not(.ytp-fullscreen)," +
  3656. ".iri-always-playing #movie_player:not(.ytp-fullscreen):not(.unstarted-mode) {" +
  3657. style +
  3658. "}";
  3659.  
  3660. }
  3661.  
  3662. },
  3663. iniMoveData: function (clientX, clientY) {
  3664.  
  3665. var video_rects;
  3666. var video_player;
  3667.  
  3668. if (video_player = document.getElementById("movie_player")) {
  3669.  
  3670. video_rects = video_player.getBoundingClientRect();
  3671.  
  3672. this.move_data.player_dimension.height = video_rects.height;
  3673. this.move_data.player_dimension.width = video_rects.width;
  3674. this.move_data.player_position.X = video_rects.left;
  3675. this.move_data.player_position.Y = video_rects.top;
  3676. this.move_data.mouse_offset.X = clientX - video_rects.left;
  3677. this.move_data.mouse_offset.Y = clientY - video_rects.top;
  3678.  
  3679. if (!user_settings.miniPlayer || !user_settings.miniPlayer.position) {
  3680.  
  3681. user_settings.miniPlayer = {
  3682. position: {
  3683. X: this.move_data.player_position.X,
  3684. Y: this.move_data.player_position.Y,
  3685. snapRight: true,
  3686. snapBottom: true
  3687. },
  3688. size: 352
  3689. };
  3690.  
  3691. }
  3692.  
  3693. }
  3694.  
  3695. },
  3696. movePlayer: function (event) {
  3697.  
  3698. if (event.type === "mousemove") {
  3699.  
  3700. document.documentElement.classList.add("iri-mini-player-moving");
  3701.  
  3702. this.move_data.player_position.X = event.clientX - this.move_data.mouse_offset.X;
  3703. this.move_data.player_position.Y = event.clientY - this.move_data.mouse_offset.Y;
  3704.  
  3705. this.hasMoved = true;
  3706. this.updatePlayerPosition(true);
  3707.  
  3708. } else if (event.type === "click" || event.type === "mouseup" || event.type === "mousedown") {
  3709.  
  3710. if (this.mouseListener) {
  3711.  
  3712. window.removeEventListener("click", this.mouseListener, true);
  3713. window.removeEventListener("mouseup", this.mouseListener, true);
  3714. window.removeEventListener("mousemove", this.mouseListener, true);
  3715.  
  3716. this.mouseListener = null;
  3717.  
  3718. }
  3719.  
  3720. switch (event.type) {
  3721. case "mousedown":
  3722.  
  3723. this.iniMoveData(event.clientX, event.clientY);
  3724.  
  3725. this.mouseListener = this.movePlayer.bind(this);
  3726.  
  3727. window.addEventListener("click", this.mouseListener, true);
  3728. window.addEventListener("mouseup", this.mouseListener, true);
  3729. window.addEventListener("mousemove", this.mouseListener, true);
  3730.  
  3731. break;
  3732. case "mouseup":
  3733. case "click":
  3734.  
  3735. document.documentElement.classList.remove("iri-mini-player-moving");
  3736.  
  3737. user_settings.miniPlayer = {
  3738. position: {
  3739. X: this.move_data.player_position.X,
  3740. Y: this.move_data.player_position.Y,
  3741. snapRight: this.move_data.player_position.snapRight,
  3742. snapBottom: this.move_data.player_position.snapBottom
  3743. },
  3744. size: 352
  3745. };
  3746.  
  3747. break;
  3748. }
  3749.  
  3750. if (this.hasMoved) {
  3751.  
  3752. iridium_api.saveSettings("miniPlayer");
  3753. this.hasMoved = false;
  3754.  
  3755. }
  3756.  
  3757. }
  3758.  
  3759. event.preventDefault();
  3760. event.stopPropagation();
  3761. return false;
  3762.  
  3763. },
  3764. setMiniPlayerSize: function (player_api, event) {
  3765.  
  3766. if (event) {
  3767. if ("fullscreen" in event) {
  3768.  
  3769. if (event.fullscreen) {
  3770. player_api.removeAttribute("style");
  3771. } else {
  3772. this.updatePlayerPosition();
  3773. }
  3774.  
  3775. }
  3776. }
  3777.  
  3778. player_api.setSizeStyle(false, true);
  3779.  
  3780. },
  3781. endMiniPlayer: function (class_name) {
  3782.  
  3783. var player_api;
  3784. var is_in_theater_mode;
  3785.  
  3786. this.move_data.is_mini = false;
  3787.  
  3788. document.documentElement.classList.remove(class_name);
  3789.  
  3790. if (!iridium_api.isPopUpPlayer && (player_api = document.getElementById("movie_player"))) {
  3791.  
  3792. is_in_theater_mode = document.querySelector("ytd-watch[theater], ytd-watch-flexy[theater]");
  3793.  
  3794. if (!document.querySelector(".iri-always-visible,.iri-always-playing")) {
  3795. player_api.removeAttribute("style");
  3796. }
  3797.  
  3798. player_api.setSizeStyle(true, is_in_theater_mode);
  3799.  
  3800. window.dispatchEvent(new Event("resize"));
  3801.  
  3802. if (this.setMiniPlayerSizeListener) {
  3803.  
  3804. player_api.removeEventListener("onFullscreenChange", this.setMiniPlayerSizeListener, false);
  3805. this.setMiniPlayerSizeListener = null;
  3806.  
  3807. }
  3808.  
  3809. if (this.setMiniPlayerSizeResizeListener) {
  3810.  
  3811. window.removeEventListener("resize", this.setMiniPlayerSizeResizeListener, false);
  3812. this.setMiniPlayerSizeResizeListener = null;
  3813.  
  3814. }
  3815.  
  3816. }
  3817.  
  3818. },
  3819. iniMiniPlayer: function (class_name) {
  3820.  
  3821. var player_api;
  3822.  
  3823. this.move_data.is_mini = true;
  3824.  
  3825. document.documentElement.classList.add(class_name);
  3826.  
  3827. if (player_api = document.getElementById("movie_player")) {
  3828.  
  3829. if (this.setMiniPlayerSizeListener) {
  3830.  
  3831. player_api.removeEventListener("onFullscreenChange", this.setMiniPlayerSizeListener, false);
  3832. delete this.setMiniPlayerSizeListener;
  3833.  
  3834. }
  3835.  
  3836. this.iniMiniPlayerControls(player_api);
  3837. this.setMiniPlayerSize(player_api);
  3838.  
  3839. this.iniMoveData(0, 0);
  3840.  
  3841. this.move_data.player_position.X = user_settings.miniPlayer.position.X;
  3842. this.move_data.player_position.Y = user_settings.miniPlayer.position.Y;
  3843.  
  3844. this.updatePlayerPosition();
  3845.  
  3846. window.dispatchEvent(new Event("resize"));
  3847.  
  3848. this.setMiniPlayerSizeListener = this.setMiniPlayerSize.bind(this, player_api);
  3849. player_api.addEventListener("onFullscreenChange", this.setMiniPlayerSizeListener);
  3850.  
  3851. this.setMiniPlayerSizeResizeListener = this.updatePlayerPosition.bind(this);
  3852. window.addEventListener("resize", this.setMiniPlayerSizeResizeListener, false);
  3853.  
  3854. }
  3855.  
  3856. },
  3857. iniAlwaysVisible: function (event) {
  3858.  
  3859. var player_bounds;
  3860. var is_out_of_sight;
  3861. var player_container;
  3862. var is_already_floating;
  3863.  
  3864. if (!user_settings.player_always_visible || document.querySelector("ytd-miniplayer-bar-renderer")) {
  3865. return;
  3866. }
  3867.  
  3868. is_already_floating = document.documentElement.classList.contains("iri-always-visible");
  3869.  
  3870. if (event.detail && event.detail.pageType !== "watch" && is_already_floating) {
  3871. this.endMiniPlayer("iri-always-visible");
  3872. } else if (window.location.pathname === "/watch") {
  3873. if ((player_container = document.querySelector("#player #player-container, #player-theater-container #player-container")) &&
  3874. (player_bounds = player_container.getBoundingClientRect())) {
  3875.  
  3876. is_out_of_sight = player_bounds.bottom < ((player_bounds.height / 2) + 50);
  3877.  
  3878. if (is_out_of_sight && !is_already_floating && player_bounds.height > 0) {
  3879. this.iniMiniPlayer("iri-always-visible");
  3880. } else if (!is_out_of_sight && is_already_floating) {
  3881. this.endMiniPlayer("iri-always-visible");
  3882. }
  3883.  
  3884. }
  3885. }
  3886.  
  3887. },
  3888. iniMiniPlayerControls: function (player_api) {
  3889.  
  3890. var move_area;
  3891. var mini_player_controls;
  3892.  
  3893. if (!(mini_player_controls = document.getElementById("iri-mini-player-controls")) && player_api) {
  3894.  
  3895. mini_player_controls = document.createElement("div");
  3896. mini_player_controls.id = "iri-mini-player-controls";
  3897.  
  3898. move_area = document.createElement("div");
  3899. move_area.id = "iri-mini-player-move";
  3900. move_area.addEventListener("mousedown", this.movePlayer.bind(this), true);
  3901.  
  3902. mini_player_controls.appendChild(move_area);
  3903.  
  3904. player_api.appendChild(mini_player_controls);
  3905.  
  3906. }
  3907.  
  3908. },
  3909. onSettingsUpdated: function () {
  3910.  
  3911. if (user_settings.miniPlayer) {
  3912.  
  3913. this.move_data.player_position.X = user_settings.miniPlayer.position.X;
  3914. this.move_data.player_position.Y = user_settings.miniPlayer.position.Y;
  3915.  
  3916. }
  3917.  
  3918. this.updatePlayerPosition();
  3919.  
  3920. },
  3921. ini: function () {
  3922.  
  3923. var always_visible_listener;
  3924.  
  3925. if (iridium_api.initializeOption.call(this)) {
  3926. return;
  3927. }
  3928.  
  3929. always_visible_listener = this.iniAlwaysVisible.bind(this);
  3930.  
  3931. window.addEventListener("scroll", always_visible_listener, false);
  3932. window.addEventListener("yt-navigate-finish", always_visible_listener, false);
  3933.  
  3934. }
  3935. },
  3936. {
  3937. options: {
  3938. player_hide_end_screen: {
  3939. id: "player_hide_end_screen",
  3940. section: "video",
  3941. sub_section: "player",
  3942. type: "checkbox",
  3943. value: false,
  3944. i18n: {
  3945. label: "Hide end screen cards on mouse hover"
  3946. }
  3947. }
  3948. },
  3949. toggleHideCards: function () {
  3950.  
  3951. if (user_settings.player_hide_end_screen) {
  3952. document.documentElement.classList.add("iri-hide-end-screen-cards");
  3953. } else {
  3954. document.documentElement.classList.remove("iri-hide-end-screen-cards");
  3955. }
  3956.  
  3957. },
  3958. onSettingsUpdated: function () {
  3959. this.toggleHideCards();
  3960. },
  3961. ini: function () {
  3962.  
  3963. if (iridium_api.initializeOption.call(this)) {
  3964. return;
  3965. }
  3966.  
  3967. this.toggleHideCards();
  3968.  
  3969. }
  3970. },
  3971. {
  3972. options: {
  3973. iridium_dark_mode: {
  3974. id: "iridium_dark_mode",
  3975. section: "settings",
  3976. sub_section: "settings",
  3977. type: "checkbox",
  3978. value: false,
  3979. i18n: {
  3980. label: "Use dark theme"
  3981. },
  3982. callback: function () {
  3983.  
  3984. if (user_settings.iridium_dark_mode) {
  3985. document.documentElement.classList.add("iri-dark-mode-settings");
  3986. } else {
  3987. document.documentElement.classList.remove("iri-dark-mode-settings");
  3988. }
  3989.  
  3990. }
  3991. }
  3992. }
  3993. },
  3994. {
  3995. options: {
  3996. iridium_user_settings: {
  3997. id: "iridium_user_settings",
  3998. section: "settings",
  3999. sub_section: "settings",
  4000. type: "custom",
  4001. i18n: {
  4002. button_save: "Save",
  4003. button_close: "Close",
  4004. button_export: "Export",
  4005. button_import: "Import",
  4006. button_reset: "Reset",
  4007. placeholder: "Paste your new settings here",
  4008. confirm_reset: "You are about to reset your settings. It is advised to backup your current settings before continuing.\n\nDo you wish to continue?\n\n",
  4009. reset_success: "Settings have been reset.\n\nChanges will be applied after a page refresh.\n\n",
  4010. confirm_import: "You are about to override your current settings. It is advised to backup your current settings before continuing.\n\nDo you wish to continue?\n\n",
  4011. import_success: "Your settings have been imported with success.\n\nChanges will be applied after a page refresh.\n\n",
  4012. import_error: "Your settings could not be imported because they appear to be invalid.\n\n"
  4013. },
  4014. custom: function () {
  4015.  
  4016. var element;
  4017. var element_list;
  4018.  
  4019. element_list = [];
  4020.  
  4021. element = document.createElement("button");
  4022. element.textContent = i18n.iridium_user_settings.button_import;
  4023. element.className = "setting iri-settings-button";
  4024. element.addEventListener("click", this.textEditor.bind(this, "import"), false);
  4025.  
  4026. element_list.push(element);
  4027.  
  4028. element = document.createElement("button");
  4029. element.textContent = i18n.iridium_user_settings.button_export;
  4030. element.className = "setting iri-settings-button";
  4031. element.addEventListener("click", this.textEditor.bind(this, "export"), false);
  4032.  
  4033. element_list.push(element);
  4034.  
  4035. element = document.createElement("button");
  4036. element.textContent = i18n.iridium_user_settings.button_reset;
  4037. element.className = "setting iri-settings-button danger";
  4038. element.addEventListener("click", this.resetSettings.bind(this), false);
  4039.  
  4040. element_list.push(element);
  4041.  
  4042. return element_list;
  4043.  
  4044. },
  4045. resetSettings: function () {
  4046.  
  4047. if (window.confirm(i18n.iridium_user_settings.confirm_reset)) {
  4048.  
  4049. user_settings = null;
  4050. iridium_api.initializeSettings();
  4051. iridium_api.saveSettings();
  4052.  
  4053. window.alert(i18n.iridium_user_settings.reset_success);
  4054.  
  4055. }
  4056.  
  4057. },
  4058. importSettings: function () {
  4059.  
  4060. var editor;
  4061. var textarea;
  4062.  
  4063. if ((textarea = document.getElementById("iridium-textarea")) && window.confirm(i18n.iridium_user_settings.confirm_import)) {
  4064. try {
  4065.  
  4066. user_settings = JSON.parse(textarea.value);
  4067.  
  4068. iridium_api.saveSettings();
  4069.  
  4070. window.alert(i18n.iridium_user_settings.import_success);
  4071.  
  4072. if (editor = document.getElementById("iridium-text-editor")) {
  4073. editor.remove();
  4074. }
  4075.  
  4076. } catch (error) {
  4077. window.alert(i18n.iridium_user_settings.import_error + error.name + ": " + error.message);
  4078. }
  4079. }
  4080.  
  4081. },
  4082. closeEditor: function (editor) {
  4083.  
  4084. editor.remove();
  4085.  
  4086. },
  4087. textEditor: function (type, event) {
  4088.  
  4089. var editor;
  4090. var button;
  4091. var textarea;
  4092. var buttons_section;
  4093.  
  4094. if (!(editor = document.getElementById("iridium-text-editor"))) {
  4095.  
  4096. editor = document.createElement("div");
  4097. editor.id = "iridium-text-editor";
  4098.  
  4099. document.body.appendChild(editor);
  4100.  
  4101. } else {
  4102. editor.textContent = "";
  4103. }
  4104.  
  4105. buttons_section = document.createElement("div");
  4106. buttons_section.id = "buttons-section";
  4107. textarea = document.createElement("textarea");
  4108. textarea.id = "iridium-textarea";
  4109. textarea.setAttribute("spellcheck", "false");
  4110.  
  4111. if (type === "import") {
  4112.  
  4113. textarea.setAttribute("placeholder", i18n.iridium_user_settings.placeholder);
  4114.  
  4115. button = document.createElement("button");
  4116. button.textContent = i18n.iridium_user_settings.button_save;
  4117. button.className = "iri-settings-button";
  4118. button.addEventListener("click", this.importSettings.bind(this), false);
  4119.  
  4120. buttons_section.appendChild(button);
  4121.  
  4122. }
  4123.  
  4124. button = document.createElement("button");
  4125. button.textContent = i18n.iridium_user_settings.button_close;
  4126. button.className = "iri-settings-button";
  4127. button.addEventListener("click", this.closeEditor.bind(this, editor), false);
  4128.  
  4129. buttons_section.appendChild(button);
  4130.  
  4131. if (type === "export") {
  4132. textarea.value = JSON.stringify(user_settings, null, 4);
  4133. }
  4134.  
  4135. editor.appendChild(buttons_section);
  4136. editor.appendChild(textarea);
  4137.  
  4138. }
  4139. },
  4140. iridium_custom_language: {
  4141. id: "iridium_custom_language",
  4142. section: "settings",
  4143. sub_section: "language",
  4144. type: "checkbox",
  4145. value: false,
  4146. i18n: {
  4147. label: "Use modified locale"
  4148. }
  4149. },
  4150. iridium_language: {
  4151. id: "iridium_language",
  4152. section: "settings",
  4153. sub_section: "language",
  4154. type: "custom",
  4155. i18n: {
  4156. button_save: "Save",
  4157. button_close: "Close",
  4158. confirm_save: "You are about to replace your extension language settings.\n\nDo you wish to continue?\n\n",
  4159. save_success: "New language saved successfully.\n\nChanges will be applied after a page refresh.\n\n",
  4160. save_error: "The new language could not be saved because it appears to be invalid.\n\n"
  4161. },
  4162. custom: function () {
  4163.  
  4164. var element;
  4165. var element_list;
  4166.  
  4167. element_list = [];
  4168.  
  4169. element = document.createElement("button");
  4170. element.textContent = i18n.language;
  4171. element.className = "setting iri-settings-button";
  4172. element.addEventListener("click", this.textEditor.bind(this), false);
  4173.  
  4174. element_list.push(element);
  4175.  
  4176. return element_list;
  4177.  
  4178. },
  4179. closeEditor: function (editor) {
  4180.  
  4181. editor.remove();
  4182.  
  4183. },
  4184. saveLanguage: function (textarea) {
  4185.  
  4186. var editor;
  4187.  
  4188. if ((textarea = document.getElementById("iridium-textarea")) && window.confirm(i18n.iridium_language.confirm_save)) {
  4189. try {
  4190.  
  4191. user_settings.custom_language = JSON.parse(textarea.value);
  4192.  
  4193. iridium_api.setCustomLanguage(user_settings.custom_language);
  4194. iridium_api.saveSettings("custom_language");
  4195.  
  4196. window.alert(i18n.iridium_language.save_success);
  4197.  
  4198. if (editor = document.getElementById("iridium-text-editor")) {
  4199. editor.remove();
  4200. }
  4201.  
  4202. } catch (error) {
  4203. window.alert(i18n.iridium_language.save_error + error.name + ": " + error.message);
  4204. }
  4205. }
  4206.  
  4207. },
  4208. textEditor: function (event) {
  4209.  
  4210. var editor;
  4211. var button;
  4212. var textarea;
  4213. var buttons_section;
  4214.  
  4215. if (!(editor = document.getElementById("iridium-text-editor"))) {
  4216.  
  4217. editor = document.createElement("div");
  4218. editor.id = "iridium-text-editor";
  4219.  
  4220. document.body.appendChild(editor);
  4221.  
  4222. } else {
  4223. editor.textContent = "";
  4224. }
  4225.  
  4226. buttons_section = document.createElement("div");
  4227. buttons_section.id = "buttons-section";
  4228.  
  4229. button = document.createElement("button");
  4230. button.textContent = i18n.iridium_language.button_save;
  4231. button.className = "iri-settings-button";
  4232. button.addEventListener("click", this.saveLanguage.bind(this), false);
  4233.  
  4234. buttons_section.appendChild(button);
  4235.  
  4236. button = document.createElement("button");
  4237. button.textContent = i18n.iridium_language.button_close;
  4238. button.className = "iri-settings-button";
  4239. button.addEventListener("click", this.closeEditor.bind(this, editor), false);
  4240.  
  4241. buttons_section.appendChild(button);
  4242.  
  4243. textarea = document.createElement("textarea");
  4244. textarea.id = "iridium-textarea";
  4245. textarea.value = JSON.stringify(i18n, null, 4);
  4246. textarea.setAttribute("spellcheck", "false");
  4247.  
  4248. editor.appendChild(buttons_section);
  4249. editor.appendChild(textarea);
  4250.  
  4251. }
  4252. }
  4253. },
  4254. google_api_locale: "",
  4255. fetchingLocale: false,
  4256. locale_base_url: "https://api.github.com/repos/ParticleCore/Iridium/contents/i18n/",
  4257. saveLanguage: function (message) {
  4258.  
  4259. var locale_updated;
  4260.  
  4261. this.fetchingLocale = false;
  4262.  
  4263. iridium_api.broadcast_channel.removeEventListener("message", this.saveLanguageListener);
  4264.  
  4265. if (message.data && message.data.payload !== "") {
  4266.  
  4267. try {
  4268.  
  4269. user_settings.i18n_locale = JSON.parse(message.data.payload);
  4270. user_settings.i18n_locale.code = this.google_api_locale;
  4271. locale_updated = true;
  4272.  
  4273. } catch (ignore) {
  4274. }
  4275.  
  4276. user_settings.iridium_language_data.next_check = new Date().getTime() + 6048E5;
  4277.  
  4278. if (locale_updated) {
  4279.  
  4280. iridium_api.saveSettings("i18n_locale");
  4281. iridium_api.saveSettings("iridium_language_data");
  4282.  
  4283. }
  4284.  
  4285. }
  4286.  
  4287. },
  4288. getLanguage: function (data) {
  4289.  
  4290. var locale_updated;
  4291.  
  4292. this.fetchingLocale = false;
  4293.  
  4294. if (data.target.readyState === 4) {
  4295. if (data.target.status === 200) {
  4296.  
  4297. try {
  4298.  
  4299. user_settings.i18n_locale = JSON.parse(data.target.response);
  4300. user_settings.i18n_locale.code = this.google_api_locale;
  4301. locale_updated = true;
  4302.  
  4303. } catch (ignore) {
  4304. }
  4305.  
  4306. user_settings.iridium_language_data.last_modified = new Date(data.target.getResponseHeader("Last-Modified")).getTime();
  4307. }
  4308. }
  4309.  
  4310. user_settings.iridium_language_data.next_check = new Date().getTime() + 6048E5;
  4311.  
  4312. if (locale_updated) {
  4313.  
  4314. iridium_api.saveSettings("i18n_locale");
  4315. iridium_api.saveSettings("iridium_language_data");
  4316.  
  4317. }
  4318.  
  4319. },
  4320. getLocale: function () {
  4321.  
  4322. this.fetchingLocale = true;
  4323.  
  4324. iridium_api.localXMLHttpRequest(
  4325. "GET",
  4326. this.getLanguage.bind(this),
  4327. this.locale_base_url + this.google_api_locale + ".json",
  4328. ["Accept", "application/vnd.github.raw"]
  4329. );
  4330.  
  4331. },
  4332. checkModified: function (data) {
  4333.  
  4334. this.fetchingLocale = false;
  4335.  
  4336. if (data.target.readyState === 4) {
  4337. if (data.target.status === 200) {
  4338. this.getLocale();
  4339. }
  4340. }
  4341.  
  4342. },
  4343. checkLocale: function () {
  4344.  
  4345. var current_time;
  4346.  
  4347. if (this.google_api_locale = iridium_api.checkIfExists("yt.config_.GAPI_LOCALE")) {
  4348.  
  4349. if (this.google_api_locale !== "en_US") {
  4350.  
  4351. if (!this.fetchingLocale) {
  4352.  
  4353. this.fetchingLocale = true;
  4354.  
  4355. if (!user_settings.iridium_language_data) {
  4356.  
  4357. current_time = new Date().getTime();
  4358.  
  4359. user_settings.iridium_language_data = {
  4360. last_modified: current_time,
  4361. next_check: current_time + 6048E5
  4362. };
  4363.  
  4364. iridium_api.saveSettings("iridium_language_data");
  4365.  
  4366. }
  4367.  
  4368. if (is_user_script) {
  4369.  
  4370. if (!user_settings.i18n_locale || user_settings.i18n_locale.code !== this.google_api_locale) {
  4371. this.getLocale();
  4372. } else if (current_time || user_settings.iridium_language_data.next_check < new Date().getTime()) {
  4373.  
  4374. iridium_api.localXMLHttpRequest(
  4375. "HEAD",
  4376. this.checkModified.bind(this),
  4377. this.locale_base_url + this.google_api_locale + ".json",
  4378. [
  4379. "If-Modified-Since",
  4380. new Date(user_settings.iridium_language_data.last_modified).toUTCString()
  4381. ]
  4382. );
  4383.  
  4384. }
  4385.  
  4386. } else if (
  4387. !user_settings.i18n_locale ||
  4388. user_settings.i18n_locale.code !== this.google_api_locale ||
  4389. user_settings.iridium_language_data.next_check < new Date().getTime()
  4390. ) {
  4391.  
  4392. this.saveLanguageListener = this.saveLanguage.bind(this);
  4393.  
  4394. iridium_api.broadcast_channel.addEventListener("message", this.saveLanguageListener);
  4395.  
  4396. window.dispatchEvent(new CustomEvent(receive_settings_from_page, {
  4397. detail: {
  4398. locale: this.google_api_locale
  4399. }
  4400. }));
  4401.  
  4402. }
  4403.  
  4404. }
  4405.  
  4406. } else if (user_settings.i18n_locale || user_settings.iridium_language_data) {
  4407.  
  4408. delete user_settings.i18n_locale;
  4409. delete user_settings.iridium_language_data;
  4410.  
  4411. iridium_api.deleteSetting("i18n_locale");
  4412. iridium_api.deleteSetting("iridium_language_data");
  4413. iridium_api.initializeSettings();
  4414.  
  4415. }
  4416.  
  4417. }
  4418.  
  4419. },
  4420. ini: function () {
  4421.  
  4422. if (iridium_api.initializeOption.call(this)) {
  4423. return;
  4424. }
  4425.  
  4426. if (!user_settings.iridium_custom_language) {
  4427. document.addEventListener("readystatechange", this.checkLocale.bind(this), false);
  4428. }
  4429.  
  4430. }
  4431. },
  4432. {
  4433. options: {
  4434. donate_paypal: {
  4435. id: "donate_paypal",
  4436. section: "donate",
  4437. sub_section: "paypal",
  4438. type: "custom",
  4439. i18n: {
  4440. one_time: "One time donation",
  4441. any_amount: "Any amount",
  4442. monthly: "Monthly donation",
  4443. one_euro: "1€",
  4444. three_euro: "3€",
  4445. five_euro: "5€",
  4446. ten_euro: "10€"
  4447. },
  4448. custom: function () {
  4449.  
  4450. var element;
  4451. var element_list;
  4452.  
  4453. element_list = [];
  4454.  
  4455. element = document.createElement("textnode");
  4456. element.textContent = i18n.donate_paypal.one_time;
  4457. element.className = "setting";
  4458.  
  4459. element_list.push(element);
  4460.  
  4461. element = document.createElement("a");
  4462. element.href = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UMVQJJFG4BFHW&lc=US";
  4463. element.target = "_blank";
  4464. element.textContent = i18n.donate_paypal.any_amount;
  4465. element.className = "setting iri-settings-button";
  4466.  
  4467. element_list.push(element);
  4468.  
  4469. element = document.createElement("br");
  4470.  
  4471. element_list.push(element);
  4472.  
  4473. element = document.createElement("textnode");
  4474. element.textContent = i18n.donate_paypal.monthly;
  4475. element.className = "setting";
  4476.  
  4477. element_list.push(element);
  4478.  
  4479. element = document.createElement("a");
  4480. element.href = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7VPKXJ49XFAPC&lc=US";
  4481. element.target = "_blank";
  4482. element.textContent = i18n.donate_paypal.one_euro;
  4483. element.className = "setting iri-settings-button";
  4484.  
  4485. element_list.push(element);
  4486.  
  4487. element = document.createElement("a");
  4488. element.href = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2G4G9HLVKSR5C&lc=US";
  4489. element.target = "_blank";
  4490. element.textContent = i18n.donate_paypal.three_euro;
  4491. element.className = "setting iri-settings-button";
  4492.  
  4493. element_list.push(element);
  4494.  
  4495. element = document.createElement("a");
  4496. element.href = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3KGWY5QQFFYCS&lc=US";
  4497. element.target = "_blank";
  4498. element.textContent = i18n.donate_paypal.five_euro;
  4499. element.className = "setting iri-settings-button";
  4500.  
  4501. element_list.push(element);
  4502.  
  4503. element = document.createElement("a");
  4504. element.href = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=U5RPAT2VUEM2N&lc=US";
  4505. element.target = "_blank";
  4506. element.textContent = i18n.donate_paypal.ten_euro;
  4507. element.className = "setting iri-settings-button";
  4508.  
  4509. element_list.push(element);
  4510.  
  4511. return element_list;
  4512.  
  4513. }
  4514. }
  4515. }
  4516. },
  4517. {
  4518. options: {
  4519. donate_patreon: {
  4520. id: "donate_patreon",
  4521. section: "donate",
  4522. sub_section: "patreon",
  4523. type: "custom",
  4524. i18n: {
  4525. patreon: "Support with Patreon"
  4526. },
  4527. custom: function () {
  4528.  
  4529. var element;
  4530. var element_list;
  4531.  
  4532. element_list = [];
  4533.  
  4534. element = document.createElement("a");
  4535. element.href = "https://www.patreon.com/particle";
  4536. element.target = "_blank";
  4537. element.textContent = i18n.donate_patreon.patreon;
  4538. element.className = "setting iri-settings-button";
  4539.  
  4540. element_list.push(element);
  4541.  
  4542. return element_list;
  4543.  
  4544. }
  4545. }
  4546. }
  4547. }
  4548. ];
  4549.  
  4550. iridium_api = {
  4551. videoIdPattern: /v=([\w-_]+)/,
  4552. isSettingsPage: window.location.pathname === "/iridium-settings",
  4553. isPopUpPlayer: window.name === "popUpPlayer",
  4554. localXMLHttpRequest: function (method, call, url, head) {
  4555.  
  4556. var request;
  4557.  
  4558. request = new XMLHttpRequest();
  4559. request.addEventListener("load", call);
  4560. request.open(method, url, true);
  4561.  
  4562. if (head && head !== "doc") {
  4563. request.setRequestHeader(head[0], head[1]);
  4564. } else {
  4565. request.responseType = "document";
  4566. }
  4567.  
  4568. request.send();
  4569.  
  4570. },
  4571. closeWelcomeBox: function (event) {
  4572.  
  4573. var welcome_box;
  4574.  
  4575. if (event.target.tagName === "BUTTON" || event.target.id === "iri-welcome-box") {
  4576. if (welcome_box = document.getElementById("iri-welcome-box")) {
  4577.  
  4578. welcome_box.remove();
  4579. user_settings.welcome_closed = true;
  4580. iridium_api.saveSettings("welcome_closed");
  4581.  
  4582. }
  4583. }
  4584.  
  4585. },
  4586. showWelcomeBox: function () {
  4587.  
  4588. var welcome_box;
  4589.  
  4590. if (!user_settings.welcome_closed && !this.isSettingsPage) {
  4591.  
  4592. if (!document.getElementById("iri-welcome-box")) {
  4593.  
  4594. welcome_box = document.createElement("template");
  4595. welcome_box.innerHTML =
  4596. "<div id='iri-welcome-box' style='display:none;'>" +
  4597. " <div id='iri-welcome-box-content'>" +
  4598. " <div style='text-align:center;' data-locale='text|thank_you'></div>" +
  4599. " <svg id='iri-welcome-icon' viewBox='0 0 24 24' style='height:48px;'>" +
  4600. " <radialGradient id='iri-welcome-gradient' gradientUnits='userSpaceOnUse' cx='6' cy='22' r='18.5'>" +
  4601. " <stop class='iri-start-gradient' offset='0'/>" +
  4602. " <stop class='iri-stop-gradient' offset='1'/>" +
  4603. " </radialGradient>" +
  4604. " <polygon points='21 12 3,1.8 3 22.2''/>" +
  4605. " <path d='M3 1.8v20.4L21 12L3 1.8z M6 7l9 5.1l-9 5.1V7z''/>" +
  4606. " </svg>" +
  4607. " <div data-locale='text|settings_instruction'></div>" +
  4608. " <hr style='opacity:0;'/>" +
  4609. " <div style='display:inline;' data-locale='text|features_instruction'></div>" +
  4610. " <a href='https://github.com/ParticleCore/Iridium/wiki/Features' target='_blank' data-locale='text|features_link'></a>" +
  4611. " <hr style='opacity:0;'/>" +
  4612. " <div data-locale='text|donate_instruction'></div>" +
  4613. " <hr style='opacity:0;'/>" +
  4614. " <h3 style='font-weight:500;'>PayPal</h3>" +
  4615. " <div style='display:inline;' data-locale='text|paypal_one_time'></div>" +
  4616. " <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UMVQJJFG4BFHW&lc=US' target='_blank' class='iri-button' data-locale='text|paypal_any_amount'></a>" +
  4617. " <hr style='opacity:0;'/>" +
  4618. " <div style='display:inline;' data-locale='text|paypal_monthly'></div>" +
  4619. " <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7VPKXJ49XFAPC&lc=US' target='_blank' class='iri-button'>1€</a>" +
  4620. " <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2G4G9HLVKSR5C&lc=US' target='_blank' class='iri-button'>3€</a>" +
  4621. " <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3KGWY5QQFFYCS&lc=US' target='_blank' class='iri-button'>5€</a>" +
  4622. " <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=U5RPAT2VUEM2N&lc=US' target='_blank' class='iri-button'>10€</a>" +
  4623. " <hr style='opacity:0;'/>" +
  4624. " <h3 style='font-weight:500;'>Patreon</h3>" +
  4625. " <a href='https://www.patreon.com/particle' target='_blank' class='iri-button' data-locale='text|patreon_support'></a>" +
  4626. " <div style='text-align:right;white-space: normal'>" +
  4627. " <button style='padding:5px 10px;' data-locale='text|button_close'></button>" +
  4628. " </div>" +
  4629. " </div>" +
  4630. "</div>";
  4631. welcome_box = welcome_box.content;
  4632. iridium_api.applyText(welcome_box, i18n.welcome_box);
  4633.  
  4634. document.documentElement.addEventListener("click", this.closeWelcomeBox.bind(this), false);
  4635. document.documentElement.appendChild(welcome_box);
  4636.  
  4637. }
  4638.  
  4639. } else if (welcome_box = document.getElementById("iri-welcome-box")) {
  4640. welcome_box.remove();
  4641.  
  4642. }
  4643.  
  4644. },
  4645. setStorage: function (id, value) {
  4646. try {
  4647. window.localStorage.setItem(id, value);
  4648. } catch (ignore) {
  4649. }
  4650. },
  4651. checkIfExists: function (path, host) {
  4652.  
  4653. var i;
  4654. var path_list;
  4655.  
  4656. host = host || window;
  4657. path_list = path.split(".");
  4658.  
  4659. for (i = 0; i < path_list.length; i++) {
  4660. if (!(host = host[path_list[i]])) {
  4661. return null;
  4662. }
  4663. }
  4664.  
  4665. return host;
  4666.  
  4667. },
  4668. applyText: function (html, text_list) {
  4669.  
  4670. var i;
  4671. var j;
  4672. var locale;
  4673. var locale_text;
  4674. var node_list;
  4675. var locale_list;
  4676.  
  4677. node_list = html.querySelectorAll("[data-locale]");
  4678.  
  4679. for (i = 0; i < node_list.length; i++) {
  4680.  
  4681. locale_list = node_list[i].dataset.locale.split("&");
  4682.  
  4683. for (j = 0; j < locale_list.length; j++) {
  4684.  
  4685. locale = locale_list[j].split("|");
  4686. locale_text = text_list[locale[1]];
  4687.  
  4688. switch (locale[0]) {
  4689. case "title":
  4690. node_list[i].setAttribute("title", locale_text);
  4691. break;
  4692. case "text":
  4693. node_list[i].appendChild(document.createTextNode(locale_text));
  4694. break;
  4695. case "tooltip":
  4696. node_list[i].tooltipText = locale_text;
  4697. break;
  4698. }
  4699.  
  4700. }
  4701.  
  4702. }
  4703.  
  4704. },
  4705. getCurrentPageData: function(path) {
  4706.  
  4707. var data;
  4708. var ytdApp;
  4709.  
  4710. if (!(ytdApp = document.querySelector("ytd-app")) || !(ytdApp = iridium_api.checkIfExists("__data__.data", ytdApp))) {
  4711. return;
  4712. }
  4713.  
  4714. return iridium_api.checkIfExists(path, ytdApp);
  4715.  
  4716. },
  4717. getSingleObjectByKey: function (obj, keys, match) {
  4718.  
  4719. var i;
  4720. var hasKey;
  4721. var result;
  4722. var property;
  4723.  
  4724. for (property in obj) {
  4725.  
  4726. if (obj.hasOwnProperty(property) && obj[property] !== null) {
  4727.  
  4728. hasKey = keys.constructor.name === "String" ? keys === property : keys.indexOf(property) > -1;
  4729.  
  4730. if (hasKey && (!match || obj[property].constructor.name !== "Object" && match(obj[property], obj))) {
  4731. return obj[property];
  4732. } else if (obj[property].constructor.name === "Object") {
  4733. if (result = this.getSingleObjectByKey(obj[property], keys, match)) {
  4734. return result;
  4735. }
  4736. } else if (obj[property].constructor.name === "Array") {
  4737. for (i = 0; i < obj[property].length; i++) {
  4738. if (result = this.getSingleObjectByKey(obj[property][i], keys, match)) {
  4739. return result;
  4740. }
  4741. }
  4742. }
  4743.  
  4744. }
  4745.  
  4746. }
  4747.  
  4748. },
  4749. getObjectByKey: function (obj, keys, match, list, pos) {
  4750.  
  4751. var i;
  4752. var hasKey;
  4753. var results;
  4754. var property;
  4755.  
  4756. results = [];
  4757.  
  4758. for (property in obj) {
  4759. if (obj.hasOwnProperty(property) && obj[property] !== null) {
  4760.  
  4761. hasKey = keys.constructor.name === "String" ? keys === property : keys.indexOf(property) > -1;
  4762.  
  4763. if (hasKey && (!match || typeof obj[property] !== "object" && match(obj[property], obj))) {
  4764.  
  4765. results.push({
  4766. target: obj,
  4767. property: property,
  4768. list: list,
  4769. pos: pos
  4770. });
  4771.  
  4772. } else if (obj[property]) {
  4773.  
  4774. if (obj[property].constructor === Object) {
  4775. results = results.concat(this.getObjectByKey(obj[property], keys, match, list, pos));
  4776. } else if (obj[property].constructor === Array) {
  4777. for (i = 0; i < obj[property].length; i++) {
  4778. results = results.concat(this.getObjectByKey(obj[property][i], keys, match, obj[property], i));
  4779. }
  4780. }
  4781.  
  4782. }
  4783.  
  4784. }
  4785. }
  4786.  
  4787. return results;
  4788.  
  4789. },
  4790. setCustomLanguage: function (custom_language) {
  4791.  
  4792. var i;
  4793. var j;
  4794. var key;
  4795. var parsed;
  4796. var sub_key;
  4797.  
  4798. try {
  4799.  
  4800. i18n = JSON.stringify(custom_language);
  4801.  
  4802. if (i18n !== "{}") {
  4803.  
  4804. i18n = JSON.parse(i18n);
  4805. parsed = true;
  4806.  
  4807. }
  4808.  
  4809. } catch (error) {
  4810. }
  4811.  
  4812. if (!parsed) {
  4813.  
  4814. i18n = default_language;
  4815. return;
  4816.  
  4817. }
  4818.  
  4819. key = Object.keys(default_language);
  4820.  
  4821. for (i = 0; i < key.length; i++) {
  4822.  
  4823. if (!(key[i] in i18n)) {
  4824. i18n[key[i]] = default_language[key[i]];
  4825. } else if (default_language[key[i]].constructor.name === "Object") {
  4826.  
  4827. sub_key = Object.keys(default_language[key[i]]);
  4828.  
  4829. for (j = 0; j < sub_key.length; j++) {
  4830. if (i18n[key[i]].constructor.name === "Object") {
  4831. if (!(sub_key[j] in i18n[key[i]])) {
  4832. i18n[key[i]][sub_key[j]] = default_language[key[i]][sub_key[j]];
  4833. }
  4834. }
  4835. }
  4836.  
  4837. }
  4838.  
  4839. }
  4840.  
  4841. },
  4842. fillSettingsContainer: function (options_list) {
  4843.  
  4844. var i;
  4845. var j;
  4846. var temp;
  4847. var input;
  4848. var label;
  4849. var select;
  4850. var header;
  4851. var option;
  4852. var options;
  4853. var section;
  4854. var setting;
  4855. var help_link;
  4856. var sub_section;
  4857.  
  4858. if (!(section = document.getElementById("settings_sub_section"))) {
  4859. return;
  4860. }
  4861.  
  4862. section.textContent = "";
  4863.  
  4864. if (header = document.getElementById("settings_section_header")) {
  4865. header.textContent = i18n.section_titles[options_list[0].section];
  4866. }
  4867.  
  4868. for (i = 0; i < options_list.length; i++) {
  4869.  
  4870. option = options_list[i];
  4871.  
  4872. if (!(sub_section = document.getElementById(i18n.sub_section_titles[option.sub_section]))) {
  4873.  
  4874. sub_section = document.createElement("div");
  4875. sub_section.id = i18n.sub_section_titles[option.sub_section];
  4876.  
  4877. header = document.createElement("h3");
  4878. header.textContent = i18n.sub_section_titles[option.sub_section];
  4879.  
  4880. sub_section.appendChild(header);
  4881. section.appendChild(sub_section);
  4882.  
  4883. }
  4884.  
  4885. setting = document.createElement("div");
  4886. setting.className = "settings_setting";
  4887.  
  4888. switch (option.type) {
  4889.  
  4890. case "checkbox":
  4891.  
  4892. input = document.createElement("input");
  4893. input.className = "setting";
  4894. input.id = option.id;
  4895. input.type = option.type;
  4896. input.checked = user_settings[option.id];
  4897.  
  4898. label = document.createElement("label");
  4899. label.textContent = i18n[option.id].label;
  4900. label.className = "setting";
  4901. label.setAttribute("for", option.id);
  4902.  
  4903. setting.appendChild(input);
  4904. setting.appendChild(label);
  4905.  
  4906. if (option.callback) {
  4907. input.callback = option.callback;
  4908. }
  4909.  
  4910. break;
  4911.  
  4912. case "dropdown":
  4913.  
  4914. label = document.createElement("label");
  4915. label.textContent = i18n[option.id].label;
  4916. label.className = "setting";
  4917. label.setAttribute("for", option.id);
  4918.  
  4919. select = document.createElement("select");
  4920. select.id = option.id;
  4921. select.className = "iri-settings-button";
  4922.  
  4923. for (j = 0; j < option.options.length; j++) {
  4924.  
  4925. options = document.createElement("option");
  4926. options.value = option.options[j];
  4927. options.textContent = i18n[option.id].options[j];
  4928.  
  4929. if (user_settings[option.id] === option.options[j]) {
  4930. options.setAttribute("selected", "true");
  4931. }
  4932.  
  4933. select.appendChild(options);
  4934. }
  4935.  
  4936. setting.appendChild(label);
  4937. setting.appendChild(select);
  4938.  
  4939. break;
  4940.  
  4941. case "custom":
  4942.  
  4943. if (option.custom) {
  4944.  
  4945. temp = option.custom();
  4946.  
  4947. for (j = 0; j < temp.length; j++) {
  4948. setting.appendChild(temp[j]);
  4949. }
  4950.  
  4951. }
  4952.  
  4953. break;
  4954.  
  4955. }
  4956.  
  4957. if (option.type !== "custom") {
  4958.  
  4959. help_link = document.createElement("a");
  4960. help_link.textContent = "?";
  4961. help_link.href = "https://github.com/ParticleCore/Iridium/wiki/Features#" + option.id;
  4962. help_link.setAttribute("title", i18n.iridium_api.feature_link);
  4963. help_link.className = "feature-link";
  4964. help_link.setAttribute("target", "features");
  4965.  
  4966. setting.appendChild(help_link);
  4967.  
  4968. }
  4969.  
  4970. sub_section.appendChild(setting);
  4971.  
  4972. }
  4973.  
  4974. },
  4975. loadSelectedSection: function () {
  4976.  
  4977. var i;
  4978. var name;
  4979. var option;
  4980. var active_id;
  4981. var options_list;
  4982. var active_sidebar;
  4983.  
  4984. if (!(active_sidebar = document.querySelector(".sidebar_section.active_sidebar"))) {
  4985. return;
  4986. }
  4987.  
  4988. active_id = active_sidebar.dataset.section;
  4989. options_list = [];
  4990.  
  4991. for (i = 0; i < modules.length; i++) {
  4992. if (modules[i].options) {
  4993. for (name in modules[i].options) {
  4994. if (modules[i].options.hasOwnProperty(name)) {
  4995.  
  4996. option = modules[i].options[name];
  4997.  
  4998. if (option.section === active_id) {
  4999. options_list.push(option);
  5000. }
  5001.  
  5002. }
  5003. }
  5004. }
  5005. }
  5006.  
  5007. iridium_api.fillSettingsContainer(options_list);
  5008.  
  5009. },
  5010. updateSidebarSelection: function (event) {
  5011.  
  5012. var next;
  5013. var current;
  5014. var sidebar_current;
  5015.  
  5016. if (event.target.dataset.section) {
  5017.  
  5018. current = document.querySelector(".active_sidebar");
  5019. next = document.getElementById("sidebar_" + event.target.dataset.section);
  5020.  
  5021. if (next !== current) {
  5022.  
  5023. if (sidebar_current = document.querySelector(".active_sidebar")) {
  5024. sidebar_current.classList.remove("active_sidebar");
  5025. }
  5026.  
  5027. event.target.classList.add("active_sidebar");
  5028.  
  5029. iridium_api.loadSelectedSection();
  5030.  
  5031. }
  5032.  
  5033. }
  5034.  
  5035. },
  5036. settingsBuilder: function (option) {
  5037.  
  5038. var header;
  5039. var divider;
  5040. var section;
  5041. var sub_section;
  5042. var sidebar_section;
  5043. var settings_sidebar;
  5044. var settings_container;
  5045.  
  5046. if (!(settings_sidebar = document.getElementById("iridium_settings_sidebar"))) {
  5047.  
  5048. settings_sidebar = document.createElement("div");
  5049. settings_sidebar.id = "iridium_settings_sidebar";
  5050.  
  5051. document.body.appendChild(settings_sidebar);
  5052.  
  5053. }
  5054.  
  5055. if (!(sidebar_section = document.getElementById("sidebar_" + option.section))) {
  5056.  
  5057. sidebar_section = document.createElement("div");
  5058. sidebar_section.id = "sidebar_" + option.section;
  5059. sidebar_section.textContent = i18n.section_list[option.section];
  5060. sidebar_section.dataset.section = option.section;
  5061.  
  5062. sidebar_section.className = "sidebar_section";
  5063. settings_sidebar.appendChild(sidebar_section);
  5064.  
  5065. }
  5066.  
  5067. if (!(settings_container = document.getElementById("iridium_settings_container"))) {
  5068.  
  5069. settings_container = document.createElement("div");
  5070. settings_container.id = "iridium_settings_container";
  5071.  
  5072. if (!(section = document.getElementById("settings_section"))) {
  5073.  
  5074. header = document.createElement("h2");
  5075. header.id = "settings_section_header";
  5076.  
  5077. divider = document.createElement("div");
  5078. divider.className = "settings_divider";
  5079.  
  5080. section = document.createElement("div");
  5081. section.id = "settings_section";
  5082.  
  5083. section.addEventListener("change", iridium_api.autoSaveSettings, true);
  5084. section.appendChild(header);
  5085. section.appendChild(divider);
  5086.  
  5087. settings_container.appendChild(section);
  5088.  
  5089. }
  5090.  
  5091. if (!(sub_section = document.getElementById("settings_sub_section"))) {
  5092.  
  5093. sub_section = document.createElement("div");
  5094. sub_section.id = "settings_sub_section";
  5095.  
  5096. section.appendChild(sub_section);
  5097.  
  5098. }
  5099.  
  5100. document.body.appendChild(settings_container);
  5101.  
  5102. }
  5103.  
  5104. if (!document.querySelector(".active_sidebar")) {
  5105. sidebar_section.classList.add("active_sidebar");
  5106. }
  5107.  
  5108. },
  5109. loadSettingsMenu: function (is_refresh) {
  5110.  
  5111. var i;
  5112. var name;
  5113. var title;
  5114. var option;
  5115. var new_section;
  5116. var current_section;
  5117.  
  5118. if (is_refresh && (current_section = document.querySelector(".sidebar_section.active_sidebar"))) {
  5119. current_section = current_section.id;
  5120. }
  5121.  
  5122. if (document.head) {
  5123. document.head.textContent = "";
  5124. } else {
  5125. document.documentElement.appendChild(document.createElement("head"));
  5126. }
  5127.  
  5128. if (document.body) {
  5129. document.body.textContent = "";
  5130. } else {
  5131. document.documentElement.appendChild(document.createElement("body"));
  5132. }
  5133.  
  5134. if (!(title = document.querySelector("title"))) {
  5135.  
  5136. title = document.createElement("title");
  5137.  
  5138. document.head.appendChild(title);
  5139.  
  5140. }
  5141.  
  5142. title.textContent = i18n.iridium_api.settings_button;
  5143. document.body.id = "iridium_settings";
  5144. document.body.style.display = "none";
  5145.  
  5146. for (i = 0; i < modules.length; i++) {
  5147. if (modules[i].options) {
  5148. for (name in modules[i].options) {
  5149. if (modules[i].options.hasOwnProperty(name)) {
  5150.  
  5151. option = modules[i].options[name];
  5152. iridium_api.settingsBuilder(option);
  5153.  
  5154. }
  5155. }
  5156. }
  5157. }
  5158.  
  5159. document.removeEventListener("click", iridium_api.updateSidebarSelection, false);
  5160. document.addEventListener("click", iridium_api.updateSidebarSelection, false);
  5161.  
  5162. if (is_refresh) {
  5163.  
  5164. if (new_section = document.querySelector(".sidebar_section.active_sidebar")) {
  5165. new_section.classList.remove("active_sidebar");
  5166. }
  5167.  
  5168. if (current_section = document.getElementById(current_section)) {
  5169. current_section.classList.add("active_sidebar");
  5170. }
  5171.  
  5172. }
  5173.  
  5174. iridium_api.loadSelectedSection();
  5175.  
  5176. },
  5177. autoSaveSettings: function (event) {
  5178.  
  5179. switch (event.target.type) {
  5180.  
  5181. case "checkbox":
  5182.  
  5183. user_settings[event.target.id] = event.target.checked;
  5184.  
  5185. break;
  5186.  
  5187. case "select-one":
  5188.  
  5189. user_settings[event.target.id] = event.target.value;
  5190.  
  5191. break;
  5192.  
  5193. }
  5194.  
  5195. if (event.target.callback) {
  5196. event.target.callback();
  5197. }
  5198.  
  5199. iridium_api.saveSettings();
  5200.  
  5201. },
  5202. deleteSetting: function (setting) {
  5203.  
  5204. window.dispatchEvent(new CustomEvent(receive_settings_from_page, {
  5205. detail: {
  5206. settings: setting,
  5207. delete: true
  5208. }
  5209. }));
  5210.  
  5211. },
  5212. saveSettings: function (single_setting) {
  5213.  
  5214. var settings;
  5215.  
  5216. if (single_setting in user_settings) {
  5217. settings = user_settings[single_setting];
  5218. } else {
  5219. settings = user_settings;
  5220. }
  5221.  
  5222. window.dispatchEvent(new CustomEvent(receive_settings_from_page, {
  5223. detail: {
  5224. settings: settings,
  5225. single_setting: single_setting
  5226. }
  5227. }));
  5228.  
  5229. },
  5230. initializeBypasses: function () {
  5231.  
  5232. var ytd_watch;
  5233. var sizeBypass;
  5234.  
  5235. if (ytd_watch = document.querySelector("ytd-watch, ytd-watch-flexy")) {
  5236.  
  5237. sizeBypass = function () {
  5238.  
  5239. var width;
  5240. var height;
  5241. var movie_player;
  5242.  
  5243. if (!ytd_watch.theater && !document.querySelector(".iri-full-browser") && (movie_player = document.querySelector("#movie_player"))) {
  5244.  
  5245. width = movie_player.offsetWidth;
  5246. height = Math.round(movie_player.offsetWidth / (16 / 9));
  5247.  
  5248. if (ytd_watch.updateStyles) {
  5249.  
  5250. ytd_watch.updateStyles({
  5251. "--ytd-watch-flexy-width-ratio": 1,
  5252. "--ytd-watch-flexy-height-ratio": 0.5625
  5253. });
  5254. ytd_watch.updateStyles({
  5255. "--ytd-watch-width-ratio": 1,
  5256. "--ytd-watch-height-ratio": 0.5625
  5257. });
  5258.  
  5259. }
  5260.  
  5261. } else {
  5262.  
  5263. width = window.NaN;
  5264. height = window.NaN;
  5265.  
  5266. }
  5267.  
  5268. return {
  5269. width: width,
  5270. height: height
  5271. };
  5272.  
  5273. };
  5274.  
  5275. if (ytd_watch.calculateCurrentPlayerSize_) {
  5276.  
  5277. if (!ytd_watch.calculateCurrentPlayerSize_.bypassed) {
  5278.  
  5279. ytd_watch.calculateCurrentPlayerSize_ = sizeBypass;
  5280. ytd_watch.calculateCurrentPlayerSize_.bypassed = true;
  5281.  
  5282. }
  5283.  
  5284. if (!ytd_watch.calculateNormalPlayerSize_.bypassed) {
  5285.  
  5286. ytd_watch.calculateNormalPlayerSize_ = sizeBypass;
  5287. ytd_watch.calculateNormalPlayerSize_.bypassed = true;
  5288.  
  5289. }
  5290.  
  5291. }
  5292. }
  5293.  
  5294. },
  5295. initializeSettings: function (new_settings) {
  5296.  
  5297. var i;
  5298. var j;
  5299. var option;
  5300. var options;
  5301. var i18n_entry;
  5302. var loaded_settings;
  5303. var iridium_settings;
  5304.  
  5305. if (iridium_settings = document.getElementById("iridium-settings")) {
  5306.  
  5307. loaded_settings = JSON.parse(iridium_settings.textContent || "null");
  5308. receive_settings_from_page = iridium_settings.getAttribute("settings-beacon-from");
  5309. send_settings_to_page = iridium_settings.getAttribute("settings-beacon-to");
  5310.  
  5311. iridium_settings.remove();
  5312.  
  5313. }
  5314.  
  5315. user_settings = new_settings || loaded_settings || user_settings || {};
  5316. i18n = default_language;
  5317.  
  5318. if (user_settings.iridium_custom_language) {
  5319. if (user_settings.custom_language) {
  5320. iridium_api.setCustomLanguage(user_settings.custom_language);
  5321. }
  5322. } else if (user_settings.i18n_locale) {
  5323. iridium_api.setCustomLanguage(user_settings.i18n_locale);
  5324. }
  5325.  
  5326. for (i = 0; i < modules.length; i++) {
  5327.  
  5328. for (options in modules[i].options) {
  5329.  
  5330. if (modules[i].options.hasOwnProperty(options)) {
  5331.  
  5332. option = modules[i].options[options];
  5333.  
  5334. if (!(option.id in user_settings) && "value" in option) {
  5335. user_settings[option.id] = option.value;
  5336. }
  5337.  
  5338. if (option.i18n) {
  5339. if (!(option.id in i18n)) {
  5340. i18n[option.id] = option.i18n;
  5341. } else if (option.i18n.constructor.name === "Object") {
  5342.  
  5343. i18n_entry = Object.keys(option.i18n);
  5344.  
  5345. for (j = 0; j < i18n_entry.length; j++) {
  5346. if (i18n[option.id].constructor.name === "Object") {
  5347. if (!(i18n_entry[j] in i18n[option.id])) {
  5348. i18n[option.id][i18n_entry[j]] = option.i18n[i18n_entry[j]];
  5349. }
  5350. }
  5351. }
  5352.  
  5353. }
  5354. }
  5355.  
  5356. }
  5357.  
  5358. }
  5359.  
  5360. }
  5361.  
  5362. this.showWelcomeBox();
  5363.  
  5364. },
  5365. initializeSettingsButton: function () {
  5366.  
  5367. var buttons;
  5368. var iridium_settings_button;
  5369.  
  5370. buttons = document.querySelector("#end #buttons");
  5371.  
  5372. if (buttons && !(iridium_settings_button = document.getElementById("iridium_settings_button"))) {
  5373.  
  5374. iridium_settings_button = document.createElement("template");
  5375. iridium_settings_button.innerHTML =
  5376. "<a id='iridium_settings_button' href='/iridium-settings' target='iridium-settings'>" +
  5377. " <svg viewBox='0 0 24 24' style='height:24px;'>" +
  5378. " <radialGradient id='iri-gradient' gradientUnits='userSpaceOnUse' cx='6' cy='22' r='18.5'>" +
  5379. " <stop class='iri-start-gradient' offset='0'/>" +
  5380. " <stop class='iri-stop-gradient' offset='1'/>" +
  5381. " </radialGradient>" +
  5382. " <polygon points='21 12 3,1.8 3 22.2'/>" +
  5383. " <path d='M3 1.8v20.4L21 12L3 1.8z M6 7l9 5.1l-9 5.1V7z'/>" +
  5384. " </svg>" +
  5385. " <div class='iri-tooltip' data-locale='text|settings_button' style='opacity: 0'></div>" +
  5386. "</a>";
  5387. iridium_settings_button = iridium_settings_button.content;
  5388. iridium_api.applyText(iridium_settings_button, i18n.iridium_api);
  5389. buttons.parentNode.insertBefore(iridium_settings_button, buttons);
  5390.  
  5391. document.documentElement.removeEventListener("load", iridium_api.initializeSettingsButton, true);
  5392.  
  5393. }
  5394.  
  5395. },
  5396. initializeModulesUpdate: function () {
  5397.  
  5398. var i;
  5399.  
  5400. for (i = 0; i < modules.length; i++) {
  5401. if (modules[i].onSettingsUpdated) {
  5402. modules[i].onSettingsUpdated();
  5403. }
  5404. }
  5405.  
  5406. },
  5407. initializeModules: function () {
  5408.  
  5409. var i;
  5410.  
  5411. for (i = 0; i < modules.length; i++) {
  5412. if (modules[i].ini) {
  5413. modules[i].ini();
  5414. }
  5415. }
  5416.  
  5417. },
  5418. initializeOption: function () {
  5419.  
  5420. var key;
  5421.  
  5422. if (this.started) {
  5423. return true;
  5424. }
  5425.  
  5426. this.started = true;
  5427.  
  5428. for (key in this.options) {
  5429. if (this.options.hasOwnProperty(key)) {
  5430. if (!(key in user_settings) && this.options[key].value) {
  5431. user_settings[key] = this.options[key].value;
  5432. }
  5433. }
  5434. }
  5435.  
  5436. return false;
  5437.  
  5438. },
  5439. initializeBroadcast: function (event) {
  5440.  
  5441. if (event.data) {
  5442.  
  5443. if (event.data.type === "settings") {
  5444.  
  5445. if (event.data.payload) {
  5446.  
  5447. if (event.data.payload.broadcast_id === this.broadcast_channel.name) {
  5448.  
  5449. this.initializeSettings(event.data.payload);
  5450. this.initializeModulesUpdate();
  5451.  
  5452. }
  5453.  
  5454. }
  5455.  
  5456. }
  5457.  
  5458. }
  5459.  
  5460. },
  5461. ini: function () {
  5462.  
  5463. this.initializeSettings();
  5464.  
  5465. this.broadcast_channel = new BroadcastChannel(user_settings.broadcast_id);
  5466. this.broadcast_channel.addEventListener("message", this.initializeBroadcast.bind(this));
  5467.  
  5468. document.documentElement.addEventListener("load", this.initializeSettingsButton, true);
  5469. document.documentElement.addEventListener("load", this.initializeBypasses, true);
  5470.  
  5471. if (this.isSettingsPage) {
  5472.  
  5473. this.loadSettingsMenu();
  5474.  
  5475. if (user_settings.iridium_dark_mode) {
  5476. document.documentElement.classList.add("iri-dark-mode-settings");
  5477. }
  5478.  
  5479. } else {
  5480. this.initializeModules();
  5481. }
  5482.  
  5483. }
  5484. };
  5485.  
  5486. iridium_api.ini();
  5487.  
  5488. },
  5489. isAllowedPage: function () {
  5490.  
  5491. var current_page;
  5492.  
  5493. if (current_page = window.location.pathname.match(/\/[a-z-]+/)) {
  5494. current_page = current_page[0];
  5495. } else {
  5496. current_page = window.location.pathname;
  5497. }
  5498.  
  5499. return [
  5500. "/tv",
  5501. "/embed",
  5502. "/live_chat",
  5503. "/account",
  5504. "/account_notifications",
  5505. "/create_channel",
  5506. "/dashboard",
  5507. "/upload",
  5508. "/webcam"
  5509. ].indexOf(current_page) < 0;
  5510.  
  5511. },
  5512. generateUUID: function () {
  5513. return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(
  5514. /[018]/g,
  5515. function (point) {
  5516. return (point ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> point / 4).toString(16);
  5517. }
  5518. );
  5519. },
  5520. saveSettings: function () {
  5521.  
  5522. if (this.is_user_script) {
  5523. this.GM.setValue(this.id, JSON.stringify(this.user_settings));
  5524. } else {
  5525. chrome.storage.local.set({iridiumSettings: this.user_settings});
  5526. }
  5527.  
  5528. },
  5529. updateSettingsOnOpenWindows: function () {
  5530. this.broadcast_channel
  5531. .postMessage({
  5532. type: "settings",
  5533. payload: this.user_settings
  5534. });
  5535. },
  5536. settingsUpdatedFromOtherWindow: function (event) {
  5537. if (event.data && event.data.broadcast_id === this.broadcast_channel.name) {
  5538.  
  5539. this.user_settings = event.data;
  5540. this.saveSettings();
  5541.  
  5542. }
  5543. },
  5544. contentScriptMessages: function (custom_event) {
  5545.  
  5546. var key;
  5547. var locale_request;
  5548. var updated_settings;
  5549.  
  5550. if ((updated_settings = custom_event.detail.settings) !== undefined) {
  5551.  
  5552. if (custom_event.detail.single_setting) {
  5553. this.user_settings[custom_event.detail.single_setting] = custom_event.detail.settings;
  5554. } else if (custom_event.detail.delete) {
  5555. if (custom_event.detail.settings in this.user_settings) {
  5556. delete this.user_settings[custom_event.detail.settings];
  5557. }
  5558. } else if (this.is_settings_page && typeof updated_settings === "object") {
  5559.  
  5560. this.user_settings = {};
  5561.  
  5562. for (key in updated_settings) {
  5563. if (updated_settings.hasOwnProperty(key)) {
  5564.  
  5565. this.user_settings = updated_settings;
  5566. break;
  5567.  
  5568. }
  5569. }
  5570.  
  5571. }
  5572.  
  5573. this.saveSettings();
  5574. this.updateSettingsOnOpenWindows();
  5575.  
  5576. } else if (locale_request = custom_event.detail.locale) {
  5577. this.broadcast_channel
  5578. .postMessage({
  5579. type: "locale",
  5580. payload: chrome.i18n.getMessage(locale_request)
  5581. });
  5582. }
  5583.  
  5584. },
  5585. initializeScript: function (event) {
  5586.  
  5587. var holder;
  5588.  
  5589. this.user_settings = event[this.id] || event;
  5590.  
  5591. if (!this.user_settings.broadcast_id) {
  5592.  
  5593. this.user_settings.broadcast_id = this.generateUUID();
  5594. this.saveSettings();
  5595.  
  5596. }
  5597.  
  5598. this.broadcast_channel = new BroadcastChannel(this.user_settings.broadcast_id);
  5599. this.broadcast_channel.addEventListener("message", this.settingsUpdatedFromOtherWindow.bind(this));
  5600.  
  5601. event = JSON.stringify(this.user_settings);
  5602.  
  5603. if (this.is_user_script) {
  5604.  
  5605. holder = document.createElement("link");
  5606. holder.rel = "stylesheet";
  5607. holder.type = "text/css";
  5608. holder.href = "https://particlecore.github.io/Iridium/css/Iridium.css?v=" + this.GM.info.script.version;
  5609. document.documentElement.appendChild(holder);
  5610.  
  5611. }
  5612.  
  5613. holder = document.createElement("iridium-settings");
  5614.  
  5615. holder.id = "iridium-settings";
  5616. holder.textContent = event;
  5617.  
  5618. holder.setAttribute("style", "display: none");
  5619. holder.setAttribute("settings-beacon-from", this.receive_settings_from_page);
  5620. holder.setAttribute("settings-beacon-to", this.send_settings_to_page);
  5621.  
  5622. document.documentElement.appendChild(holder);
  5623.  
  5624. holder = document.createElement("script");
  5625.  
  5626. holder.textContent = "(" + this.inject + "(" + this.is_user_script.toString() + "))";
  5627.  
  5628. document.documentElement.appendChild(holder);
  5629.  
  5630. holder.remove();
  5631. this.inject = null;
  5632. delete this.inject;
  5633.  
  5634. },
  5635. main: function (event) {
  5636.  
  5637. var now;
  5638. var context;
  5639.  
  5640. now = Date.now();
  5641.  
  5642. this.receive_settings_from_page = now + "-" + this.generateUUID();
  5643. this.send_settings_to_page = now + 1 + "-" + this.generateUUID();
  5644.  
  5645. window.addEventListener(
  5646. this.receive_settings_from_page,
  5647. this.contentScriptMessages.bind(this),
  5648. false
  5649. );
  5650.  
  5651. if (!event) {
  5652. if (this.is_user_script) {
  5653.  
  5654. context = this;
  5655.  
  5656. // javascript promises are horrible
  5657.  
  5658. this.GM
  5659. .getValue(this.id, "{}")
  5660. .then(function (value) {
  5661.  
  5662. event = JSON.parse(value);
  5663. context.initializeScript(event);
  5664.  
  5665. });
  5666.  
  5667. }
  5668. } else {
  5669. this.initializeScript(event);
  5670. }
  5671.  
  5672. },
  5673. ini: function () {
  5674.  
  5675. if (this.isAllowedPage()) {
  5676.  
  5677. this.is_settings_page = window.location.pathname === "/iridium-settings";
  5678. this.id = "iridiumSettings";
  5679.  
  5680. if (typeof GM === "object" || typeof GM_info === "object") {
  5681.  
  5682. this.is_user_script = true;
  5683.  
  5684. // GreaseMonkey 4 polly fill
  5685. // https://arantius.com/misc/greasemonkey/imports/greasemonkey4-polyfill.js
  5686.  
  5687. if (typeof GM === "undefined") {
  5688.  
  5689. this.GM = {
  5690. setValue: GM_setValue,
  5691. info: GM_info,
  5692. getValue: function () {
  5693. return new Promise((resolve, reject) => {
  5694. try {
  5695. resolve(GM_getValue.apply(this, arguments));
  5696. } catch (e) {
  5697. reject(e);
  5698. }
  5699. });
  5700. }
  5701. };
  5702.  
  5703. } else {
  5704. this.GM = GM;
  5705. }
  5706.  
  5707. this.main();
  5708.  
  5709. } else {
  5710.  
  5711. this.is_user_script = false;
  5712. chrome.storage.local.get(this.id, this.main.bind(this));
  5713.  
  5714. }
  5715.  
  5716. }
  5717.  
  5718. }
  5719.  
  5720. };
  5721.  
  5722. iridium.ini();
  5723.  
  5724. }());
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement