Youtube Tools

Youtube Tools All in one

  1. // ==UserScript==
  2. // @name Youtube Tools
  3. // @description Youtube Tools All in one
  4. // @version 2.2
  5. // @author Isli
  6. // @match https://*.youtube.com/*
  7. // @exclude *://music.youtube.com/*
  8. // @exclude *://*.music.youtube.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  10. // @grant GM_info
  11. // @grant GM_addStyle
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // @grant unsafeWindow
  15. // @run-at document-end
  16. // @compatible chrome
  17. // @compatible firefox
  18. // @compatible opera
  19. // @compatible safari
  20. // @compatible edge
  21. // @license MIT
  22. // @namespace https://github.com/DeveloperMDCM/
  23. // ==/UserScript==
  24. (function () {
  25. 'use strict';
  26. let validoUrl = document.location.href;
  27. const $e = (el) => document.querySelector(el); // any element
  28. const $id = (el) => document.getElementById(el); // element by id
  29. const $m = (el) => document.querySelectorAll(el); // multiple all elements
  30. const $cl = (el) => document.createElement(el); // create element
  31. const $sp = (el, pty) => document.documentElement.style.setProperty(el, pty); // set property variable css
  32. const $ap = (el) => document.body.appendChild(el); // append element
  33. const apiDislikes = "https://returnyoutubedislikeapi.com/Votes?videoId="; // Api dislikes
  34. function FormatterNumber(num, digits) {
  35. const lookup = [
  36. {
  37. value: 1,
  38. symbol: '',
  39. },
  40. {
  41. value: 1e3,
  42. symbol: ' K',
  43. },
  44. {
  45. value: 1e6,
  46. symbol: ' M',
  47. },
  48. ];
  49. const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
  50. const item = lookup
  51. .slice()
  52. .reverse()
  53. .find((item) => {
  54. return num >= item.value;
  55. });
  56. return item
  57. ? (num / item.value).toFixed(digits).replace(rx, '$1') + item.symbol
  58. : '0';
  59. }
  60. function paramsVideoURL() {
  61. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  62. return parametrosURL.get('v');
  63. }
  64. // Dislikes video
  65. async function videoDislike() {
  66. validoUrl = document.location.href;
  67. const validoVentana = $e('#below > ytd-watch-metadata > div');
  68. if (validoVentana != undefined && document.location.href.split('?v=')[0].includes('youtube.com/watch')) {
  69. validoUrl = paramsVideoURL();
  70. const urlShorts = `${apiDislikes}${validoUrl}`;
  71. try {
  72. const respuesta = await fetch(urlShorts);
  73. const datosShort = await respuesta.json();
  74. const { dislikes } = datosShort;
  75. const dislikes_content = $e('#top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div > div > dislike-button-view-model > toggle-button-view-model > button-view-model > button');
  76. if (dislikes_content !== undefined) {
  77. dislikes_content.style = 'width: 90px';
  78. dislikes_content.innerHTML = `
  79. <svg class="svg-dislike-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3" /></svg>
  80. ${FormatterNumber(dislikes, 0)}`;
  81. }
  82. } catch (error) {
  83. console.log(error);
  84. }
  85. }
  86. }
  87. // dislikes shorts
  88. async function shortDislike() {
  89. validoUrl = document.location.href;
  90. const validoVentanaShort = $m(
  91. '#dislike-button > yt-button-shape > label > div > span'
  92. );
  93. if (validoVentanaShort != undefined && document.location.href.split('/')[3] === 'shorts') {
  94. validoUrl = document.location.href.split('/')[4];
  95. const urlShorts = `${apiDislikes}${validoUrl}`;
  96. try {
  97. const respuesta = await fetch(urlShorts);
  98. const datosShort = await respuesta.json();
  99. const { dislikes } = datosShort;
  100. for (let i = 0; i < validoVentanaShort.length; i++) {
  101. validoVentanaShort[i].textContent = `${FormatterNumber(
  102. dislikes,
  103. 0
  104. )}`;
  105. }
  106. } catch (error) {
  107. console.log(error);
  108. }
  109. }
  110. }
  111. // Url change in second load
  112. let prevUrl;
  113. let showDislikes = false;
  114. setInterval(() => {
  115. const svgDislike = $e('.svg-dislike-ico'); // Check svg in dom
  116. const currUrl = window.location.href;
  117. if (prevUrl !== undefined && currUrl !== prevUrl && !svgDislike && showDislikes) {
  118. setTimeout(async() => {
  119. await videoDislike();
  120. await shortDislike();
  121. },2000)
  122. }
  123. prevUrl = currUrl;
  124. }, 1000);
  125. // Create a Trusted Types policy
  126. const policy = window.trustedTypes?.createPolicy('default', {
  127. createHTML: (input) => input,
  128. });
  129. // Styles for our enhancement panel
  130. GM_addStyle(`
  131. #cinematics {
  132. position: absolute !important;
  133. width: 90vw !important;
  134. height: 100vh ;
  135. }
  136. #cinematics div {
  137. position: fixed;
  138. inset: 0px;
  139. pointer-events: none;
  140. transform: scale(1.5, 2);
  141. }
  142. #cinematics > div > div > canvas:nth-child(1), #cinematics > div > div > canvas:nth-child(2) {
  143. position: absolute !important;
  144. width: 90vw !important;
  145. height: 100vh ;
  146. }
  147. .html5-video-player.unstarted-mode {
  148. background-repeat: no-repeat;
  149. background-position: 50% 50%;
  150. display: flex;
  151. justify-content: center;
  152. align-items: center;
  153. }
  154. #yt-enhancement-panel {
  155. position: fixed;
  156. top: 60px;
  157. right: 20px;
  158. background-color: var(--yt-enhance-menu-bg, #ffffff);
  159. color: var(--yt-enhance-menu-text, #000000);
  160. border: 1px solid #cccccc;
  161. border-radius: 8px;
  162. padding: 15px;
  163. z-index: 9999;
  164. box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  165. width: 300px;
  166. max-height: 80vh;
  167. overflow-y: auto;
  168. font-size: var(--yt-enhance-menu-font-size, 14px);
  169. }
  170. #yt-enhancement-panel h3 {
  171. margin-top: 0;
  172. color: #ff0000;
  173. }
  174. .enhancement-option {
  175. margin-bottom: 10px;
  176. }
  177. .color-picker {
  178. width: 100%;
  179. }
  180. .slider {
  181. width: 100%;
  182. }
  183. #toggle-panel {
  184. position: fixed;
  185. top: 10px;
  186. right: 180px;
  187. z-index: 10000;
  188. color: white;
  189. padding: 5px;
  190. border: none;
  191. cursor: pointer;
  192. display: flex;
  193. justify-content: center;
  194. transition: all 0.5s ease;
  195. width: 43px;
  196. border-radius: 100px;
  197. }
  198. #toggle-panel:hover {
  199. background-color: #fff;
  200. border-radius: 100px;
  201. opacity: 1 !important;
  202. }
  203. #icon-menu-settings {
  204. width: 24px;
  205. height: 24px;
  206. cursor: pointer;
  207. user-select: none;
  208. }
  209. .tab-buttons {
  210. display: flex;
  211. justify-content: space-between;
  212. margin-bottom: 15px;
  213. }
  214. .tab-button {
  215. background-color: #f0f0f0;
  216. border: none;
  217. padding: 5px 10px;
  218. cursor: pointer;
  219. border-radius: 4px;
  220. }
  221. .tab-button.active {
  222. background-color: #ff0000;
  223. color: white;
  224. }
  225. .tab-button-active {
  226. background-color: #ff0000;
  227. color: white;
  228. border: none;
  229. border-radius: 2px;
  230. }
  231. .tab-content {
  232. display: none;
  233. }
  234. .tab-content.active {
  235. display: block;
  236. }
  237. #import-export {
  238. margin-top: 15px;
  239. }
  240. #import-export textarea {
  241. width: 100%;
  242. height: 100px;
  243. }
  244. #menu-settings-icon {
  245. cursor: pointer;
  246. float: right;
  247. font-size: 20px;
  248. }
  249. .theme-option {
  250. margin-bottom: 15px;
  251. }
  252. .theme-option label {
  253. display: flex;
  254. align-items: center;
  255. }
  256. .theme-option {
  257. position: relative;
  258. width: auto;
  259. margin-bottom: 10px;
  260. padding: 10px;
  261. border-radius: 4px;
  262. cursor: pointer;
  263. }
  264. .theme-preview {
  265. position: absolute;
  266. top: 0;
  267. left: 0;
  268. right: 0;
  269. bottom: 0;
  270. border-radius: 10px;
  271. border: 1px solid #000;
  272. z-index: 1;
  273. }
  274. .theme-option input[type="radio"] {
  275. position: relative;
  276. z-index: 2;
  277. margin-right: 10px;
  278. cursor: pointer;
  279. }
  280. .theme-name {
  281. position: relative;
  282. z-index: 2;
  283. font-size: 15px;
  284. color: #fff;
  285. }
  286. .theme-option label {
  287. display: flex;
  288. align-items: center;
  289. width: 100%;
  290. position: relative;
  291. z-index: 2;
  292. }
  293. .buttons-tranlate {
  294. background: #000;
  295. font-size: 10px;
  296. border: none;
  297. color: #fbf4f4 !important;
  298. padding: 3px 0;
  299. margin-left: 10px;
  300. width: 70px;
  301. border-radius: 10px;}
  302. .buttons-tranlate:hover {
  303. cursor: pointer;
  304. background-color: #6b6b6b;}
  305. button.botones_div {
  306. margin: 0;
  307. padding: 0;
  308. }
  309. .tab-button:hover {
  310. background-color: #ec3203 !important;
  311. color: #ffffff !important;
  312. cursor: pointer;
  313. }
  314. #eyes {
  315. opacity: 0;
  316. position: absolute;
  317. height: 24px;
  318. left: 0;
  319. width: 24px;
  320. }
  321. /* width */
  322. ::-webkit-scrollbar {
  323. width: 4px;
  324. height: 10px;
  325. }
  326. /* Track */
  327. ::-webkit-scrollbar-track {
  328. background: ##d5d5d5;
  329. }
  330. /* Handle */
  331. ::-webkit-scrollbar-thumb {
  332. background: #000;
  333. }
  334. .containerButtons {
  335. display: flex;
  336. justify-content: center;
  337. align-items: center;
  338. flex-wrap: wrap;
  339. gap: 10px;
  340. }
  341. #meta.ytd-playlist-panel-video-renderer {
  342. min-width: 0;
  343. padding: 0 8px;
  344. display: flexbox;
  345. display: flex;
  346. flex-direction: column-reverse;
  347. flex: 1;
  348. flex-basis: 0.000000001px;
  349. }
  350. .containerall {
  351. display: flex;
  352. align-items: center;
  353. justify-content: center;
  354. width: 50%;
  355. margin: auto;
  356. }
  357. }
  358. .container .botoncalidades {
  359. margin: 3px 2px;
  360. width: 24.6%;
  361. }
  362. .botoncalidades:first-child {
  363. background-color: #0af;
  364. }
  365. .botoncalidades:last-child {
  366. background-color: red;
  367. width: 100px;
  368. }
  369. .selectcalidades,
  370. .botoncalidades,
  371. .selectcalidadesaudio {
  372. width: 50%;
  373. height: 27.8px;
  374. background-color: #fff;
  375. color: #000;
  376. font-size: 25px;
  377. text-align: center;
  378. border: none;
  379. font-size: 20px;
  380. margin: 2px 2px;
  381. }
  382. .botoncalidades {
  383. width: 70px;
  384. height: 30px;
  385. background-color: rgb(4, 156, 22);
  386. border: 0px solid #000;
  387. color: #fff;
  388. font-size: 20px;
  389. border-radius: 10px;
  390. margin: 2px 2px;
  391. }
  392. .botoncalidades:hover,
  393. .bntcontainer:hover {
  394. cursor: pointer;
  395. }
  396. .ocultarframe,
  397. .ocultarframeaudio {
  398. display: none;
  399. }
  400. .checked_updates {
  401. cursor: pointer;
  402. }
  403. #export-config, #import-config {
  404. width: 100%;
  405. display: flex;
  406. align-items: center;
  407. justify-content: center;
  408. gap: 10px;
  409. background-color: #ec3203;
  410. color: #ffffff;
  411. border: none;
  412. padding: 5px;
  413. }
  414. #export-config:hover, #import-config:hover {
  415. background-color: #ff0000;
  416. color: #ffffff;
  417. cursor: pointer;
  418. }
  419. `);
  420. // botons bottom video player
  421. const thumbnailVideo = `
  422. <button title="Image video" class="botones_div" type="button" id="imagen">
  423. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-photo-down" width="24"
  424. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  425. stroke-linecap="round" stroke-linejoin="round">
  426. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  427. <path d="M15 8h.01"></path>
  428. <path d="M12.5 21h-6.5a3 3 0 0 1 -3 -3v-12a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v6.5"></path>
  429. <path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l4 4"></path>
  430. <path d="M14 14l1 -1c.653 -.629 1.413 -.815 2.13 -.559"></path>
  431. <path d="M19 16v6"></path>
  432. <path d="M22 19l-3 3l-3 -3"></path>
  433. </svg>
  434. </button>
  435. `;
  436. const modeReverse = `
  437. <button title="Reverse" class="botones_div" type="button" id="invertir">
  438. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-diff" width="24"
  439. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  440. stroke-linecap="round" stroke-linejoin="round">
  441. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  442. <path d="M11 16h10"></path>
  443. <path d="M11 16l4 4"></path>
  444. <path d="M11 16l4 -4"></path>
  445. <path d="M13 8h-10"></path>
  446. <path d="M13 8l-4 4"></path>
  447. <path d="M13 8l-4 -4"></path>
  448. </svg>
  449. </button>
  450. `;
  451. const filterEyes = `
  452. <div style="position:relative; ">
  453. <button title="Filter eyes" class="botones_div" type="button">
  454. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brightness-half"
  455. width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"
  456. fill="none" stroke-linecap="round" stroke-linejoin="round">
  457. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  458. <path d="M12 9a3 3 0 0 0 0 6v-6z"></path>
  459. <path
  460. d="M6 6h3.5l2.5 -2.5l2.5 2.5h3.5v3.5l2.5 2.5l-2.5 2.5v3.5h-3.5l-2.5 2.5l-2.5 -2.5h-3.5v-3.5l-2.5 -2.5l2.5 -2.5z">
  461. </path>
  462. </svg>
  463. <input id="eyes" list="presetColors" type="color" value="#ffffff">
  464. <datalist id="presetColors">
  465. <option value="#000000" />
  466. <option value="#fbff00" />
  467. <option value="#ff0000" />
  468. <option value="#00ff00" />
  469. <option value="#0000ff" />
  470. </datalist>
  471. <div id="ojosprotect"
  472. style="position: fixed; pointer-events: none; width: 100%; height: 100%; left: 0px; top: 0px; opacity: 0.2; z-index: 10; display: block;">
  473. </div>
  474. </div>
  475. </button>
  476. `;
  477. const resetButton = `
  478. <button title="reset" class="botones_div" type="button" id="reset_button">
  479. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-power" width="24"
  480. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  481. stroke-linecap="round" stroke-linejoin="round">
  482. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  483. <path d="M7 6a7.75 7.75 0 1 0 10 0"></path>
  484. <path d="M12 4l0 8"></path>
  485. </svg>
  486. </button>
  487. `;
  488. const repeatVideo = `
  489. <button title="Repeat video" class="botones_div" type="button" id="repeatvideo">
  490. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-repeat" width="24"
  491. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  492. stroke-linecap="round" stroke-linejoin="round">
  493. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  494. <path d="M4 12v-3a3 3 0 0 1 3 -3h13m-3 -3l3 3l-3 3"></path>
  495. <path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path>
  496. </svg>
  497. </button>
  498. `;
  499. const downloadMp4Mp3 = `
  500. <button title="MP4" type="button" class="btn1 botones_div">
  501. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-download"
  502. width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  503. stroke-linecap="round" stroke-linejoin="round">
  504. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  505. <path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
  506. <path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
  507. <path d="M12 17v-6"></path>
  508. <path d="M9.5 14.5l2.5 2.5l2.5 -2.5"></path>
  509. </svg>
  510. </button>
  511. <button title="MP3" type="button" class="btn2 botones_div">
  512. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-music" width="24"
  513. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  514. stroke-linecap="round" stroke-linejoin="round">
  515. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  516. <path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
  517. <path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
  518. <path d="M11 16m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
  519. <path d="M12 16l0 -5l2 1"></path>
  520. </svg>
  521. </button>
  522. <button title="Close" type="button" class="btn3 botones_div">
  523. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="24"
  524. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  525. stroke-linecap="round" stroke-linejoin="round">
  526. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  527. <path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
  528. <path d="M10 10l4 4m0 -4l-4 4"></path>
  529. </svg>
  530. </button>
  531. `;
  532. const donwloadExternal = `
  533. <button title="External Download" type="button" class="external_link botones_div">
  534. <svg class="icon icon-tabler icon-tabler-external-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
  535. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  536. <path d="M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6"></path>
  537. <path d="M11 13l9 -9"></path>
  538. <path d="M15 4h5v5"></path>
  539. </svg>
  540. </button>
  541. `;
  542. const viewExternalVideo = `
  543. <button title="view External no cookie" type="button" class="view_external_link botones_div">
  544. <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 16m0 1a1 1 0 0 1 1 -1h3a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-3a1 1 0 0 1 -1 -1z" /><path d="M4 12v-6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-6" /><path d="M12 8h4v4" /><path d="M16 8l-5 5" /></svg>
  545. </button>
  546. `;
  547. const pictureToPicture = `
  548. <button title="Picture to picture" type="button" class="video_picture_to_picture botones_div">
  549. <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11 19h-6a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v4" /><path d="M14 14m0 1a1 1 0 0 1 1 -1h5a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-5a1 1 0 0 1 -1 -1z" /></svg>
  550. </button>
  551. `;
  552. const screenShot = `
  553. <button title="Screenshot video" type="button" class="screenshot_video botones_div">
  554. <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 8h.01" /><path d="M6 13l2.644 -2.644a1.21 1.21 0 0 1 1.712 0l3.644 3.644" /><path d="M13 13l1.644 -1.644a1.21 1.21 0 0 1 1.712 0l1.644 1.644" /><path d="M4 8v-2a2 2 0 0 1 2 -2h2" /><path d="M4 16v2a2 2 0 0 0 2 2h2" /><path d="M16 4h2a2 2 0 0 1 2 2v2" /><path d="M16 20h2a2 2 0 0 0 2 -2v-2" /></svg>
  555. </button>
  556. `;
  557. const checkUpdates = `
  558. <button title="Check new updates" type="button" class="checked_updates botones_div">
  559. <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" /><path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" /></svg>
  560. </button>
  561. `;
  562. const menuBotones = `
  563. <main>
  564. <div class="container">
  565. <form>
  566. <div class="containerButtons">
  567. ${thumbnailVideo}
  568. ${modeReverse}
  569. ${filterEyes}
  570. ${resetButton}
  571. ${repeatVideo}
  572. ${downloadMp4Mp3}
  573. ${donwloadExternal}
  574. ${viewExternalVideo}
  575. ${pictureToPicture}
  576. ${screenShot}
  577. ${checkUpdates}
  578. </div>
  579. <div>
  580. </div>
  581. </form>
  582. </div>
  583. <div class="content_collapsible_colors" style="margin-top: 10px">
  584. <form class="formulariodescarga" action="">
  585. <div class="containerall">
  586. <select class="selectcalidades ocultarframe" required>
  587. <option selected disabled>Calidad del video / Quality video</option>
  588. <option value="360">360p Mp4</option>
  589. <option value="480">480p Mp4</option>
  590. <option value="720">720p HD Mp4 Default</option>
  591. <option value="1080">1080p FULL HD Mp4</option>
  592. <option value="4k">2160p 4K WEBM</option>
  593. <option value="8k">4320p 8K WEBM</option>
  594. </select>
  595. <iframe id="descargando" style="z-index: 99; border: none; height: 27.4px; width: 50%;" class="containerall ocultarframe" src="" frameborder="0"></iframe>
  596. </div>
  597. </form>
  598. <form class="formulariodescargaaudio" action="">
  599. <div class="containerall">
  600. <select class="selectcalidadesaudio ocultarframeaudio" required>
  601. <option selected disabled>Calidad del Audio / Quality Audio</option>
  602. <option value="flac">Audio FLAC UHQ</option>
  603. <option value="wav">Audio WAV UHQ</option>
  604. <option value="mp3">Audio MP3 Default</option>
  605. <option value="m4a">Audio M4A</option>
  606. <option value="aac">Audio AAC</option>
  607. <option value="opus">Audio OPUS</option>
  608. <option value="ogg">Audio OGG</option>
  609. </select>
  610. <iframe id="descargandomp3" style="z-index: 99; border: none; height: 27.4px; width: 50%;" class="containerall ocultarframeaudio" src="" frameborder="0"></iframe>
  611. </iframe>
  612. </div>
  613. </form>
  614. </main>
  615. </html>
  616. `;
  617. // Define themes
  618. const themes = [
  619. {
  620. name: 'Default / Reload Page',
  621. gradient: '',
  622. textColor: '',
  623. raised: '',
  624. btnTranslate: '',
  625. CurrentProgressVideo: '',
  626. videoDuration: '',
  627. colorIcons: '',
  628. textLogo: '',
  629. primaryColor: '',
  630. secondaryColor: '',
  631. },
  632. {
  633. name: 'Midnight Blue',
  634. gradient: 'linear-gradient(135deg, #1e3a8a, #3b82f6)',
  635. textColor: '#ffffff',
  636. raised: '#f00',
  637. btnTranslate: '#000',
  638. CurrentProgressVideo: '#0f0',
  639. videoDuration: '#fff',
  640. colorIcons: '#fff',
  641. textLogo: '#f00',
  642. },
  643. {
  644. name: 'Forest Green',
  645. gradient: 'linear-gradient(135deg, #14532d, #22c55e)',
  646. textColor: '#ffffff',
  647. raised: '#303131',
  648. btnTranslate: '#000',
  649. CurrentProgressVideo: '#0f0',
  650. videoDuration: '#fff',
  651. colorIcons: '#fff',
  652. textLogo: '#f00',
  653. },
  654. {
  655. name: 'Sunset Orange',
  656. gradient: 'linear-gradient(135deg, #7c2d12, #f97316)',
  657. textColor: '#ffffff',
  658. raised: '#303131',
  659. btnTranslate: '#000',
  660. CurrentProgressVideo: '#0f0',
  661. videoDuration: '#fff',
  662. colorIcons: '#fff',
  663. textLogo: '#f00',
  664. },
  665. {
  666. name: 'Royal Purple',
  667. gradient: 'linear-gradient(135deg, #4c1d95, #8b5cf6)',
  668. textColor: '#ffffff',
  669. raised: '#303131',
  670. btnTranslate: '#000',
  671. CurrentProgressVideo: '#0f0',
  672. videoDuration: '#fff',
  673. colorIcons: '#fff',
  674. textLogo: '#f00',
  675. },
  676. {
  677. name: 'Cherry Blossom',
  678. gradient: 'linear-gradient(135deg, #a9005c, #fc008f)',
  679. textColor: '#ffffff',
  680. raised: '#fc008f',
  681. btnTranslate: '#000',
  682. CurrentProgressVideo: '#0f0',
  683. videoDuration: '#fff',
  684. colorIcons: '#fff',
  685. textLogo: '#f00',
  686. },
  687. {
  688. name: 'Red Dark',
  689. gradient: 'linear-gradient(135deg, #790909, #f70131)',
  690. textColor: '#ffffff',
  691. raised: '#303131',
  692. btnTranslate: '#000',
  693. CurrentProgressVideo: '#0f0',
  694. videoDuration: '#fff',
  695. colorIcons: '#fff',
  696. textLogo: '#f00',
  697. },
  698. {
  699. name: 'Raind ',
  700. gradient: 'linear-gradient(90deg, #3f5efb 0%, #fc466b) 100%',
  701. textColor: '#ffffff',
  702. raised: '#303131',
  703. btnTranslate: '#000',
  704. CurrentProgressVideo: '#0f0',
  705. videoDuration: '#fff',
  706. colorIcons: '#fff',
  707. textLogo: '#f00',
  708. },
  709. {
  710. name: 'Neon',
  711. gradient: 'linear-gradient(273deg, #ee49fd 0%, #6175ff 100%)',
  712. textColor: '#ffffff',
  713. raised: '#303131',
  714. btnTranslate: '#000',
  715. CurrentProgressVideo: '#0f0',
  716. videoDuration: '#fff',
  717. colorIcons: '#fff',
  718. textLogo: '#f00',
  719. },
  720. {
  721. name: 'Azure',
  722. gradient: 'linear-gradient(273deg, #0172af 0%, #74febd 100%)',
  723. textColor: '#ffffff',
  724. raised: '#303131',
  725. btnTranslate: '#000',
  726. CurrentProgressVideo: '#0f0',
  727. videoDuration: '#fff',
  728. colorIcons: '#fff',
  729. textLogo: '#f00',
  730. },
  731. {
  732. name: 'Butterfly',
  733. gradient: 'linear-gradient(273deg, #ff4060 0%, #fff16a 100%)',
  734. textColor: '#ffffff',
  735. raised: '#303131',
  736. btnTranslate: '#000',
  737. CurrentProgressVideo: '#0f0',
  738. videoDuration: '#fff',
  739. colorIcons: '#fff',
  740. textLogo: '#f00',
  741. },
  742. {
  743. name: 'Colombia',
  744. gradient:
  745. 'linear-gradient(174deg, #fbf63f 0%, #0000bb 45%, #ff0000 99%)',
  746. textColor: '#ffffff',
  747. raised: '#303131',
  748. btnTranslate: '#000',
  749. CurrentProgressVideo: '#0f0',
  750. videoDuration: '#fff',
  751. colorIcons: '#fff',
  752. textLogo: '#f00',
  753. },
  754. ];
  755. // Create our enhancement panel
  756. const panel = $cl('div');
  757. panel.id = 'yt-enhancement-panel';
  758. // Generate theme options HTML
  759. const themeOptionsHTML = themes
  760. .map(
  761. (theme, index) => `
  762. <label >
  763. <div class="theme-option">
  764. <div class="theme-preview" style="background: ${theme.gradient};"></div>
  765. <input type="radio" name="theme" value="${index}" ${
  766. index === 0 ? 'checked' : ''
  767. }>
  768. <span style="${theme.name === 'Default / Reload Page' ? 'color: red; ' : '' }" class="theme-name">${theme.name}</span>
  769. </div>
  770. </label>
  771. `
  772. )
  773. .join('');
  774. // find atribute dark in dom
  775. const htmlElement = $e('html');
  776. const isDarkMode = htmlElement.hasAttribute('dark');
  777. let isDarkModeActive = isDarkMode;
  778. // Use Trusted Types to set innerHTML
  779. const panelHTML = policy
  780. ? policy.createHTML(`
  781. <div style="display: flex;justify-content: space-between;align-items: center;gap: 3px;margin-bottom: 10px;">
  782. <h4 style="display: flex;align-items: center;gap: 10px;">YouTube Tools v2.2.92 <a target="_blank" href="https://github.com/DeveloperMDCM/Youtube-tools-extension">
  783. <svg style="background-color: white; border-radius: 5px;color: #000;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" /></svg>
  784. </a></h4>
  785. <div style="display: flex; gap: 5px;">
  786. <span id="menu-settings-icon">⚙️</span>
  787. <a href="https://update.gf.qytechs.cn/scripts/460680/Youtube%20Tools%20All%20in%20one%20local%20download%20mp3%20mp4%20HIGT%20QUALITY%20return%20dislikes%20and%20more.user.js" target="_blank" class="checked_updates">🔄️</a>
  788. <span style="cursor: pointer" class="close_menu_settings">❎</span>
  789. </div>
  790. </div>
  791. <div class="tab-buttons">
  792. <button class="tab-button active" data-tab="general">General</button>
  793. <button class="tab-button" data-tab="themes">Themes</button>
  794. <button class="tab-button" data-tab="sidebar">Sidebar</button>
  795. <button class="tab-button" data-tab="headers">Header</button>
  796. </div>
  797. <div id="general" class="tab-content active">
  798. <div class="enhancement-option">
  799. <label>
  800. <input type="checkbox" id="hide-comments-toggle"> Hide Comments
  801. </label>
  802. </div>
  803. <div class="enhancement-option">
  804. <label>
  805. <input type="checkbox" id="hide-sidebar-toggle"> Hide Sidebar
  806. </label>
  807. </div>
  808. <div class="enhancement-option">
  809. <label>
  810. <input type="checkbox" id="autoplay-toggle"> Disable Autoplay
  811. </label>
  812. </div>
  813. <div class="enhancement-option">
  814. <label>
  815. <input type="checkbox" id="subtitles-toggle"> Disable Subtitles
  816. </label>
  817. </div>
  818. <div class="enhancement-option">
  819. <label>
  820. <input type="checkbox" id="dislikes-toggle"> Show Dislikes / Reload page
  821. </label>
  822. </div>
  823. <div class="enhancement-option">
  824. <label>
  825. <input type="checkbox" id="themes-toggle"> Active Themes / Reload page
  826. </label>
  827. </div>
  828. <div class="enhancement-option">
  829. <label>Video Player Size: <span id="player-size-value">100</span>%</label> <button class="tab-button-active" id="reset-player-size">Reset video size</button>
  830. <input type="range" id="player-size-slider" class="slider" min="50" max="150" value="100">
  831. </div>
  832. <div class="enhancement-option">
  833. <label>Default video player quality: </label>
  834. <select class="tab-button-active" id="select-video-qualitys-select">
  835. <option value="144">144</option>
  836. <option value="240">240</option>
  837. <option value="360">360</option>
  838. <option value="480">480</option>
  839. <option value="720">720</option>
  840. <option value="1080">1080</option>
  841. <option value="1440">1440</option>
  842. <option value="2160">2160</option>
  843. </select>
  844. </div>
  845. </div>
  846. <div id="themes" class="tab-content" style="height: auto; max-height: 350px; overflow-y: auto;">
  847. <div class="themes-hidden">
  848. <h4>Choose a Theme</h4>
  849. <p>Disable cinematic Lighting</p>
  850. <label>
  851. <div class="theme-option">
  852. <div class="theme-preview" style="background: dark;"></div>
  853. <input type="radio" name="theme" value="custom">
  854. <span class="theme-name">Custom</span>
  855. </div>
  856. </label>
  857. <label>
  858. <div class="theme-option theme-selected-normal">
  859. <div class="theme-preview" style="background: dark;"></div>
  860. <input type="radio" name="theme" value="normal">
  861. <span class="theme-name">Selected Themes</span>
  862. </div>
  863. </label>
  864. <p>${isDarkModeActive ? '' : 'activate dark mode to use themes'}</p>
  865. <div class="themes-options">
  866. ${themeOptionsHTML}
  867. </div>
  868. <div class="theme-custom-options">
  869. <div class="enhancement-option">
  870. <label>Progressbar Video:</label>
  871. <input type="color" id="progressbar-color-picker" class="color-picker" value="#ff0000">
  872. </div>
  873. <div class="enhancement-option">
  874. <label>Background Color:</label>
  875. <input type="color" id="bg-color-picker" class="color-picker" value="#000000">
  876. </div>
  877. <div class="enhancement-option">
  878. <label>Primary Color:</label>
  879. <input type="color" id="primary-color-picker" class="color-picker" value="#ffffff">
  880. </div>
  881. <div class="enhancement-option">
  882. <label>Secondary Color:</label>
  883. <input type="color" id="secondary-color-picker" class="color-picker" value="#ffffff">
  884. </div>
  885. <div class="enhancement-option">
  886. <label>Header Color:</label>
  887. <input type="color" id="header-color-picker" class="color-picker" value="#000000">
  888. </div>
  889. <div class="enhancement-option">
  890. <label>Icons Color:</label>
  891. <input type="color" id="icons-color-picker" class="color-picker" value="#ffffff">
  892. </div>
  893. <div class="enhancement-option">
  894. <label>Menu Color:</label>
  895. <input type="color" id="menu-color-picker" class="color-picker" value="#000000">
  896. </div>
  897. <div class="enhancement-option">
  898. <label>Line Color Preview:</label>
  899. <input type="color" id="line-color-picker" class="color-picker" value="#ff0000">
  900. </div>
  901. <div class="enhancement-option">
  902. <label>Time Color Preview:</label>
  903. <input type="color" id="time-color-picker" class="color-picker" value="#ffffff">
  904. </div>
  905. </div>
  906. </div>
  907. </div>
  908. <div id="sidebar" class="tab-content">
  909. <h4>Available in next update</h4>
  910. </div>
  911. <div id="headers" class="tab-content">
  912. <h4>Available in next update</h4>
  913. </div>
  914. <div id="menu-settings" class="tab-content">
  915. <h4 style="margin: 10px 0">Menu Appearance</h4>
  916. <div class="enhancement-option">
  917. <label>Menu Background Color:</label>
  918. <input type="color" id="menu-bg-color-picker" class="color-picker" value="#000000">
  919. </div>
  920. <div class="enhancement-option">
  921. <label>Menu Text Color:</label>
  922. <input type="color" id="menu-text-color-picker" class="color-picker" value="#ff0000">
  923. </div>
  924. </div>
  925. <div id="import-export">
  926. <div style="display: flex;width: 100%;justify-content: space-between;">
  927. <button id="export-config">Export
  928. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 3v4a1 1 0 0 0 1 1h4" /><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" /><path d="M9 15h6" /><path d="M12.5 17.5l2.5 -2.5l-2.5 -2.5" /></svg>
  929. </button>
  930. <button id="import-config">Import
  931. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 3v4a1 1 0 0 0 1 1h4" /><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" /><path d="M15 15h-6" /><path d="M11.5 17.5l-2.5 -2.5l2.5 -2.5" /></svg>
  932. </button>
  933. </div>
  934. <textarea id="config-data" placeholder="Paste configuration here to import"></textarea>
  935. </div>
  936. `)
  937. : `
  938. <div style="display: flex;justify-content: space-between;align-items: center;gap: 3px;margin-bottom: 10px;">
  939. <h4 style="display: flex;align-items: center;gap: 10px;">YouTube Tools v2.2.92 <a target="_blank" href="https://github.com/DeveloperMDCM/Youtube-tools-extension">
  940. <svg style="background-color: white; border-radius: 5px;color: #000;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" /></svg>
  941. </a></h4>
  942. <div style="display: flex; gap: 5px;">
  943. <span id="menu-settings-icon">⚙️</span>
  944. <a href="https://update.gf.qytechs.cn/scripts/460680/Youtube%20Tools%20All%20in%20one%20local%20download%20mp3%20mp4%20HIGT%20QUALITY%20return%20dislikes%20and%20more.user.js" target="_blank" class="checked_updates">🔄️</a>
  945. <span style="cursor: pointer" class="close_menu_settings">❎</span>
  946. </div>
  947. </div>
  948. <div class="tab-buttons">
  949. <button class="tab-button active" data-tab="general">General</button>
  950. <button class="tab-button" data-tab="themes">Themes</button>
  951. <button class="tab-button" data-tab="sidebar">Sidebar</button>
  952. <button class="tab-button" data-tab="headers">Header</button>
  953. </div>
  954. <div id="general" class="tab-content active">
  955. <div class="enhancement-option">
  956. <label>
  957. <input type="checkbox" id="hide-comments-toggle"> Hide Comments
  958. </label>
  959. </div>
  960. <div class="enhancement-option">
  961. <label>
  962. <input type="checkbox" id="hide-sidebar-toggle"> Hide Sidebar
  963. </label>
  964. </div>
  965. <div class="enhancement-option">
  966. <label>
  967. <input type="checkbox" id="autoplay-toggle"> Disable Autoplay
  968. </label>
  969. </div>
  970. <div class="enhancement-option">
  971. <label>
  972. <input type="checkbox" id="subtitles-toggle"> Disable Subtitles
  973. </label>
  974. </div>
  975. <div class="enhancement-option">
  976. <label>
  977. <input type="checkbox" id="dislikes-toggle"> Show Dislikes / Reload page
  978. </label>
  979. </div>
  980. <div class="enhancement-option">
  981. <label>
  982. <input type="checkbox" id="themes-toggle"> Active Themes / Reload page
  983. </label>
  984. </div>
  985. <div class="enhancement-option">
  986. <label>Video Player Size: <span id="player-size-value">100</span>%</label> <button class="tab-button-active" id="reset-player-size">Reset video size</button>
  987. <input type="range" id="player-size-slider" class="slider" min="50" max="150" value="100">
  988. </div>
  989. <div class="enhancement-option">
  990. <label>Default video player quality: </label>
  991. <select class="tab-button-active" id="select-video-qualitys-select">
  992. <option value="144">144</option>
  993. <option value="240">240</option>
  994. <option value="360">360</option>
  995. <option value="480">480</option>
  996. <option value="720">720</option>
  997. <option value="1080">1080</option>
  998. <option value="1440">1440</option>
  999. <option value="2160">2160</option>
  1000. </select>
  1001. </div>
  1002. </div>
  1003. <div id="themes" class="tab-content" style="height: auto; max-height: 350px; overflow-y: auto;">
  1004. <div class="themes-hidden">
  1005. <h4>Choose a Theme</h4>
  1006. <p>Disable cinematic Lighting</p>
  1007. <label>
  1008. <div class="theme-option">
  1009. <div class="theme-preview" style="background: dark;"></div>
  1010. <input type="radio" name="theme" value="custom">
  1011. <span class="theme-name">Custom</span>
  1012. </div>
  1013. </label>
  1014. <label>
  1015. <div class="theme-option theme-selected-normal">
  1016. <div class="theme-preview" style="background: dark;"></div>
  1017. <input type="radio" name="theme" value="normal">
  1018. <span class="theme-name">Selected Themes</span>
  1019. </div>
  1020. </label>
  1021. <p>${isDarkModeActive ? '' : 'activate dark mode to use themes'}</p>
  1022. <div class="themes-options">
  1023. ${themeOptionsHTML}
  1024. </div>
  1025. <div class="theme-custom-options">
  1026. <div class="enhancement-option">
  1027. <label>Progressbar Video:</label>
  1028. <input type="color" id="progressbar-color-picker" class="color-picker" value="#ff0000">
  1029. </div>
  1030. <div class="enhancement-option">
  1031. <label>Background Color:</label>
  1032. <input type="color" id="bg-color-picker" class="color-picker" value="#000000">
  1033. </div>
  1034. <div class="enhancement-option">
  1035. <label>Primary Color:</label>
  1036. <input type="color" id="primary-color-picker" class="color-picker" value="#ffffff">
  1037. </div>
  1038. <div class="enhancement-option">
  1039. <label>Secondary Color:</label>
  1040. <input type="color" id="secondary-color-picker" class="color-picker" value="#ffffff">
  1041. </div>
  1042. <div class="enhancement-option">
  1043. <label>Header Color:</label>
  1044. <input type="color" id="header-color-picker" class="color-picker" value="#000000">
  1045. </div>
  1046. <div class="enhancement-option">
  1047. <label>Icons Color:</label>
  1048. <input type="color" id="icons-color-picker" class="color-picker" value="#ffffff">
  1049. </div>
  1050. <div class="enhancement-option">
  1051. <label>Menu Color:</label>
  1052. <input type="color" id="menu-color-picker" class="color-picker" value="#000000">
  1053. </div>
  1054. <div class="enhancement-option">
  1055. <label>Line Color Preview:</label>
  1056. <input type="color" id="line-color-picker" class="color-picker" value="#ff0000">
  1057. </div>
  1058. <div class="enhancement-option">
  1059. <label>Time Color Preview:</label>
  1060. <input type="color" id="time-color-picker" class="color-picker" value="#ffffff">
  1061. </div>
  1062. </div>
  1063. </div>
  1064. </div>
  1065. <div id="sidebar" class="tab-content">
  1066. <h4>Available in next update</h4>
  1067. </div>
  1068. <div id="headers" class="tab-content">
  1069. <h4>Available in next update</h4>
  1070. </div>
  1071. <div id="menu-settings" class="tab-content">
  1072. <h4 style="margin: 10px 0">Menu Appearance</h4>
  1073. <div class="enhancement-option">
  1074. <label>Menu Background Color:</label>
  1075. <input type="color" id="menu-bg-color-picker" class="color-picker" value="#000000">
  1076. </div>
  1077. <div class="enhancement-option">
  1078. <label>Menu Text Color:</label>
  1079. <input type="color" id="menu-text-color-picker" class="color-picker" value="#ff0000">
  1080. </div>
  1081. </div>
  1082. <div id="import-export">
  1083. <div style="display: flex;width: 100%;justify-content: space-between;">
  1084. <button id="export-config" style="width: 100%;display: flex;align-items: center;justify-content: center;">Export
  1085. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 3v4a1 1 0 0 0 1 1h4" /><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" /><path d="M9 15h6" /><path d="M12.5 17.5l2.5 -2.5l-2.5 -2.5" /></svg>
  1086. </button>
  1087. <button id="import-config" style="width: 100%;display: flex;align-items: center;justify-content: center;">Import
  1088. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 3v4a1 1 0 0 0 1 1h4" /><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" /><path d="M15 15h-6" /><path d="M11.5 17.5l-2.5 -2.5l2.5 -2.5" /></svg>
  1089. </button>
  1090. </div>
  1091. <textarea id="config-data" placeholder="Paste configuration here to import"></textarea>
  1092. </div>
  1093. `;
  1094. panel.innerHTML = panelHTML;
  1095. $ap(panel);
  1096. // Create toggle button
  1097. const toggleButton = $cl('div');
  1098. toggleButton.id = 'toggle-panel';
  1099. const icon = $cl('img');
  1100. icon.id = 'icon-menu-settings';
  1101. icon.src =
  1102. 'https://cdn.iconscout.com/icon/premium/png-512-thumb/settings-782-1095915.png?f=webp&w=256';
  1103. toggleButton.appendChild(icon);
  1104. // Add panel and toggle button to the page
  1105. $ap(panel);
  1106. $ap(toggleButton);
  1107. // Toggle panel visibility
  1108. let openMenu = false;
  1109. toggleButton.addEventListener('click', () => {
  1110. openMenu = !openMenu;
  1111. // openMenu
  1112. // ? (toggleButton.style.backgroundColor = '#f00')
  1113. // : (toggleButton.style.backgroundColor = 'transparent');
  1114. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  1115. });
  1116. const close_menu_settings = $e('.close_menu_settings');
  1117. close_menu_settings.addEventListener('click', () => {
  1118. openMenu = !openMenu;
  1119. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  1120. });
  1121. // Tab functionality
  1122. const tabButtons = $m('.tab-button');
  1123. const tabContents = $m('.tab-content');
  1124. tabButtons.forEach((button) => {
  1125. button.addEventListener('click', () => {
  1126. const tabName = button.getAttribute('data-tab');
  1127. tabButtons.forEach((btn) => btn.classList.remove('active'));
  1128. tabContents.forEach((content) => content.classList.remove('active'));
  1129. button.classList.add('active');
  1130. $id(tabName).classList.add('active');
  1131. });
  1132. });
  1133. // Menu settings icon functionality
  1134. $id('menu-settings-icon').addEventListener('click', () => {
  1135. tabButtons.forEach((btn) => btn.classList.remove('active'));
  1136. tabContents.forEach((content) => content.classList.remove('active'));
  1137. $id('menu-settings').classList.add('active');
  1138. });
  1139. // Function to save settings
  1140. function saveSettings() {
  1141. const settings = {
  1142. theme: $e('input[name="theme"]:checked').value,
  1143. bgColorPicker: $id('bg-color-picker').value,
  1144. progressbarColorPicker: $id('progressbar-color-picker').value,
  1145. primaryColorPicker: $id('primary-color-picker').value,
  1146. secondaryColorPicker: $id('secondary-color-picker').value,
  1147. headerColorPicker: $id('header-color-picker').value,
  1148. iconsColorPicker: $id('icons-color-picker').value,
  1149. menuColorPicker: $id('menu-color-picker').value,
  1150. lineColorPicker: $id('line-color-picker').value,
  1151. timeColorPicker: $id('time-color-picker').value,
  1152. dislikes: $id('dislikes-toggle').checked,
  1153. themes: $id('themes-toggle').checked,
  1154. hideComments: $id('hide-comments-toggle').checked,
  1155. hideSidebar: $id('hide-sidebar-toggle').checked,
  1156. disableAutoplay: $id('autoplay-toggle').checked,
  1157. // cinematicLighting: $id('cinematic-lighting-toggle').checked,
  1158. disableSubtitles: $id('subtitles-toggle').checked,
  1159. // fontSize: $id('font-size-slider').value,
  1160. playerSize: $id('player-size-slider').value,
  1161. selectVideoQuality: $id('select-video-qualitys-select').value,
  1162. menuBgColor: $id('menu-bg-color-picker').value,
  1163. menuTextColor: $id('menu-text-color-picker').value,
  1164. // menuFontSize: $id('menu-font-size-slider').value,
  1165. };
  1166. GM_setValue('ytSettingsMDCM', JSON.stringify(settings));
  1167. }
  1168. // Function to load settings
  1169. function loadSettings() {
  1170. const settings = JSON.parse(GM_getValue('ytSettingsMDCM', '{}'));
  1171. if (settings.theme) {
  1172. $e(`input[name="theme"][value="${settings.theme}"]`).checked = true;
  1173. }
  1174. $id('bg-color-picker').value = settings.bgColorPicker || '#000000';
  1175. $id('progressbar-color-picker').value = settings.progressbarColorPicker || '#ff0000';
  1176. $id('primary-color-picker').value = settings.primaryColorPicker || '#ffffff';
  1177. $id('secondary-color-picker').value = settings.secondaryColorPicker || '#ffffff';
  1178. $id('header-color-picker').value = settings.headerColorPicker || '#000';
  1179. $id('icons-color-picker').value = settings.iconsColorPicker || '#ffffff';
  1180. $id('menu-color-picker').value = settings.menuColorPicker || '#000';
  1181. $id('line-color-picker').value = settings.lineColorPicker || '#ff0000';
  1182. $id('time-color-picker').value = settings.timeColorPicker || '#ffffff';
  1183. $id('dislikes-toggle').checked = settings.dislikes || true;
  1184. $id('themes-toggle').checked = settings.themes || false;
  1185. $id('hide-comments-toggle').checked = settings.hideComments || false;
  1186. $id('hide-sidebar-toggle').checked = settings.hideSidebar || false;
  1187. $id('autoplay-toggle').checked = settings.disableAutoplay || false;
  1188. // $id('cinematic-lighting-toggle').checked = settings.cinematicLighting || false;
  1189. $id('subtitles-toggle').checked = settings.disableSubtitles || false;
  1190. // $id('font-size-slider').value = settings.fontSize || 16;
  1191. $id('player-size-slider').value = settings.playerSize || 100;
  1192. $id('select-video-qualitys-select').value = settings.selectVideoQuality || '720';
  1193. $id('menu-bg-color-picker').value = settings.menuBgColor || '#000000';
  1194. $id('menu-text-color-picker').value = settings.menuTextColor || '#ffffff';
  1195. // $id('menu-font-size-slider').value = settings.menuFontSize || 14;
  1196. updateSliderValues();
  1197. setTimeout(() => {
  1198. applySettings();
  1199. if(settings.dislikes) {
  1200. videoDislike();
  1201. shortDislike();
  1202. showDislikes = true;
  1203. }
  1204. }, 500);
  1205. }
  1206. // Function to update slider values
  1207. function updateSliderValues() {
  1208. // $id('font-size-value').textContent = $id('font-size-slider').value;
  1209. $id('player-size-value').textContent = $id('player-size-slider').value;
  1210. // $id('menu-font-size-value').textContent = $id('menu-font-size-slider').value;
  1211. }
  1212. $id('reset-player-size').addEventListener('click', () => {
  1213. $id('player-size-slider').value = 100;
  1214. updateSliderValues();
  1215. applySettings();
  1216. });
  1217. // Function to apply settings
  1218. function applySettings() {
  1219. const formulariodescarga = $e('.formulariodescarga');
  1220. const formulariodescargaaudio = $e('.formulariodescargaaudio');
  1221. if (formulariodescarga != undefined) {
  1222. formulariodescarga.classList.add('ocultarframe');
  1223. formulariodescargaaudio.classList.add('ocultarframe');
  1224. }
  1225. const settings = {
  1226. theme: $e('input[name="theme"]:checked').value,
  1227. bgColorPicker: $id('bg-color-picker').value,
  1228. progressbarColorPicker: $id('progressbar-color-picker').value,
  1229. primaryColorPicker: $id('primary-color-picker').value,
  1230. secondaryColorPicker: $id('secondary-color-picker').value,
  1231. headerColorPicker: $id('header-color-picker').value,
  1232. iconsColorPicker: $id('icons-color-picker').value,
  1233. menuColorPicker: $id('menu-color-picker').value,
  1234. lineColorPicker: $id('line-color-picker').value,
  1235. timeColorPicker: $id('time-color-picker').value,
  1236. dislikes: $id('dislikes-toggle').checked,
  1237. themes: $id('themes-toggle').checked,
  1238. hideComments: $id('hide-comments-toggle').checked,
  1239. hideSidebar: $id('hide-sidebar-toggle').checked,
  1240. disableAutoplay: $id('autoplay-toggle').checked,
  1241. // cinematicLighting: $id('cinematic-lighting-toggle').checked,
  1242. disableSubtitles: $id('subtitles-toggle').checked,
  1243. // fontSize: $id('font-size-slider').value,
  1244. playerSize: $id('player-size-slider').value,
  1245. selectVideoQuality: $id('select-video-qualitys-select').value,
  1246. menuBgColor: $id('menu-bg-color-picker').value,
  1247. menuTextColor: $id('menu-text-color-picker').value,
  1248. // menuFontSize: $id('menu-font-size-slider').value,
  1249. };
  1250. renderizarButtons();
  1251. function isFullscreen() {
  1252. return document.fullscreenElement !== null;
  1253. }
  1254. document.addEventListener("fullscreenchange", () => {
  1255. let panel = $e('#toggle-panel');
  1256. if (isFullscreen()) {
  1257. panel.style.opacity = 0;
  1258. } else {
  1259. panel.style.opacity = 1;
  1260. }
  1261. });
  1262. // Hide comments
  1263. const commentsSection = $id('comments');
  1264. if (commentsSection) {
  1265. commentsSection.style.display = settings.hideComments ? 'none' : 'block';
  1266. }
  1267. // Active inactive Themes
  1268. const themesMenuSection = $e('.themes-hidden');
  1269. if (themesMenuSection) {
  1270. themesMenuSection.style.display = settings.themes ? 'block' : 'none';
  1271. }
  1272. // Hide sidebar
  1273. const sidebarSection = $e('#secondary > #secondary-inner');
  1274. if (sidebarSection) {
  1275. sidebarSection.classList.add('side-moi');
  1276. const sidebarSection2 = $e('.side-moi');
  1277. sidebarSection2.style.display = settings.hideSidebar ? 'none' : 'block';
  1278. }
  1279. // Disable autoplay
  1280. const autoplayToggle = $e('.ytp-autonav-toggle-button');
  1281. if (autoplayToggle) {
  1282. const isCurrentlyOn =
  1283. autoplayToggle.getAttribute('aria-checked') === 'true';
  1284. if (settings.disableAutoplay && isCurrentlyOn) {
  1285. autoplayToggle.click();
  1286. } else if (!settings.disableAutoplay && !isCurrentlyOn) {
  1287. autoplayToggle.click();
  1288. }
  1289. }
  1290. // Disable subtitles
  1291. const subtitleToggle = $e('.ytp-subtitles-button');
  1292. if (subtitleToggle) {
  1293. const isCurrentlyOn =
  1294. subtitleToggle.getAttribute('aria-pressed') === 'true';
  1295. if (settings.disableSubtitles && isCurrentlyOn) {
  1296. subtitleToggle.click();
  1297. } else if (!settings.disableSubtitles && !isCurrentlyOn) {
  1298. subtitleToggle.click();
  1299. }
  1300. }
  1301. // Disable cinematicLighting
  1302. // const buttonSettingVideo = $e(".ytp-settings-button");
  1303. // if(buttonSettingVideo && !settings.cinematicLighting) {
  1304. // buttonSettingVideo.click();
  1305. // setTimeout(() => {
  1306. // buttonSettingVideo.click();
  1307. // },50)
  1308. // }
  1309. // Adjust font size
  1310. // $e('body').style.fontSize = `${settings.fontSize}px`;
  1311. // Adjust player size
  1312. const player = $e('video');
  1313. if (player) {
  1314. player.style.transform = `scale(${settings.playerSize / 100})`;
  1315. }
  1316. // selected video quality
  1317. const video = $e('div#movie_player');
  1318. let ytPlayerQuality = localStorage.getItem('yt-player-quality');
  1319. $e('#select-video-qualitys-select').addEventListener('change', () => {
  1320. applySettings();
  1321. })
  1322. if (video != undefined) {
  1323. if (ytPlayerQuality) {
  1324. let qualitySettings = JSON.parse(ytPlayerQuality);
  1325. qualitySettings.data = JSON.stringify({ quality: settings.selectVideoQuality, previousQuality: 240 });
  1326. localStorage.setItem('yt-player-quality', JSON.stringify(qualitySettings));
  1327. } else {
  1328. let defaultQualitySettings = {
  1329. data: JSON.stringify({ quality: 720, previousQuality: 240 }),
  1330. expiration: Date.now() + (365 * 24 * 60 * 60 * 1000),
  1331. creation: Date.now()
  1332. };
  1333. localStorage.setItem('yt-player-quality', JSON.stringify(defaultQualitySettings));
  1334. }
  1335. }
  1336. // Apply menu appearance settings
  1337. $sp('--yt-enhance-menu-bg', settings.menuBgColor);
  1338. $sp('--yt-enhance-menu-text', settings.menuTextColor);
  1339. // $sp('--yt-enhance-menu-font-size', `${settings.menuFontSize}px`);
  1340. // Apply theme
  1341. const selectedTheme = themes[settings.theme];
  1342. const isThemeCustom = $e(`input[name="theme"][value="custom"]`).checked;
  1343. const isThemeNormal = $e(`input[name="theme"][value="normal"]`).checked;
  1344. const themeCustomOptions = $e('.theme-custom-options');
  1345. const themeNormal = $e('.theme-selected-normal');
  1346. if(isThemeCustom != undefined) {
  1347. themeNormal.style.display = "block"
  1348. themeCustomOptions.style.display = "block";
  1349. $e('.themes-options').style.display = "none";
  1350. }
  1351. if(isThemeNormal) {
  1352. $e(`input[name="theme"][value="custom"]`).checked = false;
  1353. }
  1354. function checkDarkMode() {
  1355. if(settings.themes) {
  1356. if (isDarkMode && !isThemeCustom) {
  1357. // Apply theme
  1358. $e('.themes-options').style.display = "block";
  1359. themeNormal.style.display = "none";
  1360. themeCustomOptions.style.display = "none";
  1361. if(settings.theme === 'normal') {
  1362. $e(`input[name="theme"][value="0"]`).checked = true;
  1363. // applySettings();
  1364. } else {
  1365. $sp('--yt-spec-base-background', selectedTheme.gradient);
  1366. $sp('--yt-spec-text-primary', selectedTheme.textColor);
  1367. $sp('--yt-spec-text-secondary', selectedTheme.textColor);
  1368. $sp('--yt-spec-menu-background', selectedTheme.gradient);
  1369. $sp('--yt-spec-icon-inactive', selectedTheme.textColor);
  1370. $sp('--yt-spec-brand-icon-inactive', selectedTheme.textColor);
  1371. $sp('--yt-spec-brand-icon-active', selectedTheme.gradient);
  1372. $sp('--yt-spec-static-brand-red', selectedTheme.gradient); // line current time
  1373. $sp('--yt-spec-raised-background', selectedTheme.raised);
  1374. $sp('--yt-spec-static-brand-red', selectedTheme.CurrentProgressVideo);
  1375. $sp('--yt-spec-static-brand-white', selectedTheme.textColor);
  1376. $sp('--ytd-searchbox-background', selectedTheme.gradient);
  1377. $sp('--ytd-searchbox-text-color', selectedTheme.textColor);
  1378. GM_addStyle(`
  1379. .botones_div {
  1380. background-color: transparent;
  1381. border: none;
  1382. color: #999999;
  1383. user-select: none;
  1384. }
  1385. .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox {
  1386. background: ${selectedTheme.gradient} !important;
  1387. }
  1388. #background.ytd-masthead { background: ${selectedTheme.gradient} !important; }
  1389. .ytp-swatch-background-color {
  1390. background: ${
  1391. selectedTheme.gradient
  1392. } !important;
  1393. }
  1394. #shorts-container, #page-manager.ytd-app {
  1395. background: ${selectedTheme.gradient.replace(/(#[0-9a-fA-F]{6})/g, `$1${36}`)};
  1396. }
  1397. ytd-engagement-panel-title-header-renderer[shorts-panel] #header.ytd-engagement-panel-title-header-renderer {
  1398. background: ${selectedTheme.gradient} !important;}
  1399. .buttons-tranlate {
  1400. background: ${selectedTheme.btnTranslate} !important;
  1401. }
  1402. .badge-shape-wiz--thumbnail-default {
  1403. color: ${selectedTheme.videoDuration} !important;
  1404. background: ${selectedTheme.gradient} !important;
  1405. }
  1406. #logo-icon {
  1407. color: ${selectedTheme.textLogo} !important;
  1408. }
  1409. .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--text {
  1410. color: ${selectedTheme.iconsColor} !important;
  1411. }
  1412. .ytd-topbar-menu-button-renderer #button.ytd-topbar-menu-button-renderer {
  1413. color: ${selectedTheme.iconsColor} !important;
  1414. }
  1415. .yt-spec-icon-badge-shape--style-overlay .yt-spec-icon-badge-shape__icon {
  1416. color: ${selectedTheme.iconsColor} !important;
  1417. }
  1418. .ytp-svg-fill {
  1419. fill: ${selectedTheme.iconsColor} !important;
  1420. }
  1421. #ytp-id-30,#ytp-id-17,#ytp-id-19,#ytp-id-20{
  1422. fill: ${selectedTheme.iconsColor} !important;
  1423. }
  1424. `);
  1425. }
  1426. } else {
  1427. $sp('--yt-spec-base-background', settings.bgColorPicker);
  1428. $sp('--yt-spec-text-primary', settings.primaryColorPicker);
  1429. $sp('--yt-spec-text-secondary', settings.secondaryColorPicker);
  1430. $sp('--yt-spec-menu-background', settings.menuColorPicker);
  1431. $sp('--yt-spec-icon-inactive', settings.iconsColorPicker);
  1432. $sp('--yt-spec-brand-icon-inactive', settings.primaryColorPicker);
  1433. $sp('--yt-spec-brand-icon-active', settings.primaryColorPicker);
  1434. $sp('--yt-spec-raised-background', settings.headerColorPicker);
  1435. $sp('--yt-spec-static-brand-red', settings.lineColorPicker);
  1436. $sp('--yt-spec-static-brand-white', settings.timeColorPicker);
  1437. $sp('--ytd-searchbox-background', settings.primaryColorPicker);
  1438. $sp('--ytd-searchbox-text-color', settings.secondaryColorPicker);
  1439. GM_addStyle(`
  1440. .botones_div {
  1441. background-color: transparent;
  1442. border: none;
  1443. color: ${settings.iconsColorPicker} !important;
  1444. user-select: none;
  1445. }
  1446. .ytp-volume-slider-handle:before, .ytp-volume-slider-handle, .ytp-tooltip.ytp-preview:not(.ytp-text-detail){
  1447. background-color:
  1448. }
  1449. #container.ytd-searchbox {
  1450. color: red !important;
  1451. }
  1452. .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox {
  1453. background: ${settings.primaryColorPicker} !important;
  1454. }
  1455. .yt-spec-icon-shape {
  1456. display: flex;
  1457. align-items: center;
  1458. justify-content: center;
  1459. width: 100%;
  1460. height: 100%;
  1461. color: ${settings.iconsColorPicker} !important;
  1462. }
  1463. .ytp-time-current, .ytp-time-separator, .ytp-time-duration {
  1464. color: ${settings.iconsColorPicker} !important;
  1465. }
  1466. #background.ytd-masthead { background: ${settings.headerColorPicker} !important; }
  1467. .ytp-swatch-background-color {
  1468. background: ${
  1469. settings.progressbarColorPicker
  1470. } !important;
  1471. }
  1472. #shorts-container, #page-manager.ytd-app {
  1473. background: ${settings.bgColorPicker}36;
  1474. }
  1475. ytd-engagement-panel-title-header-renderer[shorts-panel] #header.ytd-engagement-panel-title-header-renderer {
  1476. background: ${settings.bgColorPicker} !important;}
  1477. .badge-shape-wiz--thumbnail-default {
  1478. color: ${settings.timeColorPicker} !important;
  1479. background: ${settings.secondaryColor} !important;
  1480. }
  1481. #logo-icon {
  1482. color: ${settings.primaryColorPicker} !important;
  1483. }
  1484. .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--text {
  1485. color: ${settings.iconsColorPicker} !important;
  1486. }
  1487. .ytd-topbar-menu-button-renderer #button.ytd-topbar-menu-button-renderer {
  1488. color: ${settings.iconsColorPicker} !important;
  1489. }
  1490. .yt-spec-icon-badge-shape--style-overlay .yt-spec-icon-badge-shape__icon {
  1491. color: ${settings.iconsColorPicker} !important;
  1492. }
  1493. .ytp-svg-fill {
  1494. fill: ${settings.iconsColorPicker} !important;
  1495. }
  1496. #ytp-id-30,#ytp-id-17,#ytp-id-19,#ytp-id-20{
  1497. fill: ${settings.iconsColorPicker} !important;
  1498. }
  1499. `);
  1500. }
  1501. } else {
  1502. GM_addStyle(`
  1503. .botones_div {
  1504. background-color: transparent;
  1505. border: none;
  1506. color: #ccc !important;
  1507. user-select: none;
  1508. }
  1509. `)
  1510. }
  1511. }
  1512. checkDarkMode();
  1513. let currentUrl = window.location.href;
  1514. let urlCheckInterval = setInterval(function () {
  1515. if (window.location.href !== currentUrl) {
  1516. currentUrl = window.location.href;
  1517. checkUrlChange();
  1518. }
  1519. }, 1000);
  1520. function checkUrlChange() {
  1521. setTimeout(() => {
  1522. applySettings();
  1523. }, 1000);
  1524. clearInterval(urlCheckInterval);
  1525. }
  1526. let traducido; // Texto traducido
  1527. let urlLista; // Url lista
  1528. async function traductor() {
  1529. const texto = $m('#content-text');
  1530. let o = `?client=dict-chrome-ex&sl=auto&tl=${navigator.language}&q=`;
  1531. for (let i = 0; i < texto.length; i++) {
  1532. const botonTraducir = $cl('BUTTON');
  1533. botonTraducir.classList.add('buttons-tranlate');
  1534. botonTraducir.textContent = 'Translate';
  1535. botonTraducir.setAttribute('id', `btn${i}`);
  1536. texto[i].insertAdjacentElement('afterend', botonTraducir);
  1537. const mdcm = $m(`.buttons-tranlate`);
  1538. mdcm[i].onclick = function () {
  1539. traducido = o;
  1540. urlLista = traducido + texto[i].textContent;
  1541. fetch('https://translate.googleapis.com/translate_a/t' + urlLista) //API
  1542. .then((response) => response.json())
  1543. .then((datos) => {
  1544. texto[i].textContent = datos[0][0];
  1545. mdcm[i].textContent = 'Translated';
  1546. });
  1547. };
  1548. }
  1549. }
  1550. // clean buttoms dom
  1551. function limpiarHTML(element) {
  1552. const buttons = $m(`${element}`);
  1553. [].forEach.call(buttons, function (buttons) {
  1554. buttons.remove();
  1555. });
  1556. traductor();
  1557. }
  1558. window.onscroll = () => {
  1559. const divEl = $e('#content-text');
  1560. const divEl2 = $e(
  1561. 'ytd-item-section-renderer[static-comments-header] #contents'
  1562. );
  1563. if (divEl != undefined || divEl2 != undefined) {
  1564. limpiarHTML('.buttons-tranlate');
  1565. }
  1566. };
  1567. const targetNode = $e('body');
  1568. if (targetNode != undefined) {
  1569. const element = $e('ytd-item-section-renderer[static-comments-header] #contents');
  1570. if(element != undefined) {
  1571. const observerElementDom = (elem) => {
  1572. const observer = new IntersectionObserver(entries => {
  1573. if(entries[0].isIntersecting) {
  1574. element.style.background = `${selectedTheme.gradient ?? ''}`;
  1575. } else {return}
  1576. })
  1577. return observer.observe($e(`${elem}`))
  1578. }
  1579. observerElementDom('ytd-item-section-renderer[static-comments-header] #contents')
  1580. }
  1581. }
  1582. saveSettings();
  1583. }
  1584. let validoBotones = true;
  1585. function renderizarButtons() {
  1586. const addButton = $e('.style-scope .ytd-watch-metadata');
  1587. const addButton2 = $e('#contents');
  1588. if (addButton != undefined && validoBotones) {
  1589. validoBotones = false;
  1590. const isVisible = !!(
  1591. addButton.offsetWidth ||
  1592. addButton.offsetHeight ||
  1593. addButton.getClientRects().length
  1594. );
  1595. if (isVisible) {
  1596. addButton.insertAdjacentHTML("beforebegin", menuBotones);
  1597. } else if (addButton2 != undefined) {
  1598. addButton.insertAdjacentHTML("beforebegin", menuBotones);
  1599. }
  1600. }
  1601. // Formulario de botones para descargar
  1602. const formulariodescarga = $e(
  1603. '.formulariodescarga'
  1604. );
  1605. const formulariodescargaaudio = $e(
  1606. '.formulariodescargaaudio'
  1607. );
  1608. const framedescarga = $e('#descargando');
  1609. const framedescargamp3 = $e('#descargandomp3');
  1610. if (formulariodescarga && formulariodescargaaudio) {
  1611. formulariodescarga.addEventListener('click', (e) => {
  1612. e.preventDefault();
  1613. });
  1614. formulariodescargaaudio.addEventListener('click', (e) => {
  1615. e.preventDefault();
  1616. });
  1617. }
  1618. const btn1mp4 = $e('.btn1');
  1619. const btn2mp3 = $e('.btn2');
  1620. const btn3cancel = $e('.btn3');
  1621. const selectcalidades = $e('.selectcalidades');
  1622. const selectcalidadesaudio = $e(
  1623. '.selectcalidadesaudio'
  1624. );
  1625. if(selectcalidades != undefined) {
  1626. selectcalidades.addEventListener('change', (e) => {
  1627. framedescarga.src = `https://loader.to/api/button/?url=${window.location.href}&f=${e.target.value}&color=0af`;
  1628. framedescarga.classList.remove('ocultarframe');
  1629. });
  1630. }
  1631. if(selectcalidadesaudio != undefined) {
  1632. selectcalidadesaudio.addEventListener('change', (e) => {
  1633. framedescargamp3.src = `https://loader.to/api/button/?url=${window.location.href}&f=${e.target.value}&color=049c16`;
  1634. // console.log(e.target.value)
  1635. framedescargamp3.classList.remove('ocultarframeaudio');
  1636. });
  1637. }
  1638. if (btn3cancel != undefined) {
  1639. btn3cancel.onclick = () => {
  1640. formulariodescarga.style.display = 'none';
  1641. formulariodescargaaudio.style.display = 'none';
  1642. };
  1643. }
  1644. if (btn1mp4 != undefined) {
  1645. btn1mp4.onclick = () => {
  1646. selectcalidades.classList.remove('ocultarframe');
  1647. framedescarga.classList.add('ocultarframe');
  1648. formulariodescarga.classList.remove('ocultarframe');
  1649. formulariodescarga.style.display = '';
  1650. selectcalidadesaudio.classList.add('ocultarframeaudio');
  1651. formulariodescargaaudio.classList.add('ocultarframe');
  1652. formulariodescarga.reset();
  1653. };
  1654. }
  1655. if (btn2mp3 != undefined) {
  1656. btn2mp3.onclick = () => {
  1657. formulariodescargaaudio.classList.remove('ocultarframe');
  1658. formulariodescarga.classList.add('ocultarframe');
  1659. framedescargamp3.classList.remove('ocultarframeaudio');
  1660. formulariodescargaaudio.style.display = '';
  1661. selectcalidadesaudio.classList.remove('ocultarframeaudio');
  1662. framedescargamp3.classList.add('ocultarframeaudio');
  1663. formulariodescargaaudio.reset();
  1664. };
  1665. }
  1666. // Invertir contenido
  1667. // const background_image = $e('#background_image');
  1668. // const color_bg = $e('#color_bg');
  1669. // const alertShown = localStorage.getItem('alertShown');
  1670. // const alertShownBg = localStorage.getItem('alertShownBg');
  1671. // if (!alertShown) {
  1672. // color_bg.addEventListener('change', () => {
  1673. // alert('disable cinematic mode in the video');
  1674. // localStorage.setItem('alertShown', true);
  1675. // });
  1676. // }
  1677. // if (!alertShownBg) {
  1678. // background_image.addEventListener('input', () => {
  1679. // alert('disable cinematic mode in the video');
  1680. // localStorage.setItem('alertShownBg', true);
  1681. // });
  1682. // }
  1683. const btnImagen = $e('#imagen');
  1684. const formularioButtons = $e('#eyes');
  1685. const invertirVista = $e('#invertir');
  1686. const reverse = $e('#columns');
  1687. let countViewRow = 0; // Count
  1688. if (invertirVista != undefined) {
  1689. invertirVista.onclick = () => {
  1690. countViewRow += 1;
  1691. switch (countViewRow) {
  1692. case 1:
  1693. reverse.style.flexDirection = 'row-reverse';
  1694. break;
  1695. case 2:
  1696. reverse.style.flexDirection = 'row';
  1697. countViewRow = 0;
  1698. break;
  1699. }
  1700. };
  1701. }
  1702. // valido modo oscuro y venta de video
  1703. // Repeat video button
  1704. let countRepeat = 0; // count
  1705. const repeat = $e('#repeatvideo'); // Repeat button
  1706. const imarepeat = $e('.icon-tabler-repeat'); // img repeat
  1707. const videoFull = $e(
  1708. '#movie_player > div.html5-video-container > video'
  1709. );
  1710. if(repeat != undefined) {
  1711. repeat.onclick = () => {
  1712. if (
  1713. $e('#cinematics > div') != undefined ||
  1714. videoFull != undefined
  1715. ) {
  1716. countRepeat += 1;
  1717. setInterval(() => {
  1718. switch (countRepeat) {
  1719. case 1:
  1720. document
  1721. .querySelector(
  1722. '#movie_player > div.html5-video-container > video'
  1723. )
  1724. .setAttribute('loop', 'true');
  1725. imarepeat.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-repeat-off" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
  1726. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  1727. <path d="M4 12v-3c0 -1.336 .873 -2.468 2.08 -2.856m3.92 -.144h10m-3 -3l3 3l-3 3"></path>
  1728. <path d="M20 12v3a3 3 0 0 1 -.133 .886m-1.99 1.984a3 3 0 0 1 -.877 .13h-13m3 3l-3 -3l3 -3"></path>
  1729. <path d="M3 3l18 18"></path>
  1730. </svg> `; // img repeat
  1731. break;
  1732. case 2:
  1733. countRepeat = 0;
  1734. document
  1735. .querySelector(
  1736. '#movie_player > div.html5-video-container > video'
  1737. )
  1738. .removeAttribute('loop');
  1739. imarepeat.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-repeat" width="24"
  1740. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  1741. stroke-linecap="round" stroke-linejoin="round">
  1742. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  1743. <path d="M4 12v-3a3 3 0 0 1 3 -3h13m-3 -3l3 3l-3 3"></path>
  1744. <path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path>
  1745. </svg>`;
  1746. break;
  1747. }
  1748. }, 1000);
  1749. }
  1750. }
  1751. }
  1752. // Background transparent
  1753. const cinematica = $e('#cinematics > div');
  1754. if (cinematica != undefined) {
  1755. cinematica.style =
  1756. 'position: fixed; inset: 0px; pointer-events: none; transform: scale(1.5, 2)';
  1757. }
  1758. const btnReset = $e('#reset_button'); // Reset button
  1759. if (btnReset != undefined) {
  1760. btnReset.addEventListener('click', function () {
  1761. if (localStorage.getItem('colores') != null) {
  1762. localStorage.removeItem('colores');
  1763. $e('#ojosprotect').style.backgroundColor =
  1764. 'transparent';
  1765. setTimeout(() => {
  1766. location.reload();
  1767. }, 400);
  1768. }
  1769. });
  1770. }
  1771. if (btnImagen != undefined) {
  1772. btnImagen.onclick = () => {
  1773. if (
  1774. $e('#cinematics > div') != undefined ||
  1775. videoFull != undefined
  1776. ) {
  1777. const parametrosURL = new URLSearchParams(window.location.search);
  1778. let enlace = parametrosURL.get('v');
  1779. // Construir la URL de la imagen
  1780. const imageUrl = `https://i.ytimg.com/vi/${enlace}/maxresdefault.jpg`;
  1781. // Realizar la solicitud para obtener la imagen
  1782. fetch(imageUrl)
  1783. .then((response) => {
  1784. if (!response.ok) {
  1785. throw new Error(`HTTP error! Status: ${response.status}`);
  1786. }
  1787. return response.blob();
  1788. })
  1789. .then((blob) => {
  1790. // Obtener el tamaño de la imagen en kilobytes
  1791. const imageSizeKB = blob.size / 1024;
  1792. // Verificar si el tamaño de la imagen es menor o igual a 20 KB
  1793. if (imageSizeKB >= 20) {
  1794. window.open(
  1795. `https://i.ytimg.com/vi/${enlace}/maxresdefault.jpg`,
  1796. 'popUpWindow',
  1797. 'height=500,width=400,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes'
  1798. );
  1799. // Crear una URL para la imagen
  1800. const imageUrlObject = URL.createObjectURL(blob);
  1801. // Crear un enlace para descargar la imagen
  1802. const enlaceDescarga = $cl('a');
  1803. enlaceDescarga.href = imageUrlObject;
  1804. const titleVideo = $e(
  1805. 'h1.style-scope.ytd-watch-metadata'
  1806. ).innerText;
  1807. enlaceDescarga.download = `${titleVideo}_maxresdefault.jpg`;
  1808. // Simular un clic en el enlace para iniciar la descarga
  1809. enlaceDescarga.click();
  1810. // Limpiar la URL del objeto después de la descarga
  1811. URL.revokeObjectURL(imageUrlObject);
  1812. } else {
  1813. console.log(
  1814. 'La imagen no excede los 20 KB. No se descargará.'
  1815. );
  1816. }
  1817. })
  1818. .catch((error) => {
  1819. alert('No found image');
  1820. console.error('Error al obtener la imagen:', error);
  1821. });
  1822. }
  1823. };
  1824. }
  1825. // for background image file photo higt quality
  1826. // const fileInput = document.getElementById('background_image');
  1827. // const backgroundDiv = $e('ytd-app');
  1828. // const storedImage = localStorage.getItem('backgroundImage');
  1829. // if (storedImage) {
  1830. // backgroundDiv.style = `background-size: contain; background-repeat: repeat; background-image: url(${storedImage}) !important`;
  1831. // }
  1832. // fileInput.addEventListener('change', (event) => {
  1833. // const file = event.target.files[0];
  1834. // if (file) {
  1835. // const reader = new FileReader();
  1836. // reader.onload = function (e) {
  1837. // const imageUrl = e.target.result;
  1838. // localStorage.setItem('backgroundImage', imageUrl);
  1839. // backgroundDiv.style.backgroundImage = `url(${imageUrl})`;
  1840. // };
  1841. // reader.readAsDataURL(file);
  1842. // }
  1843. // });
  1844. const externalLink = $e('.external_link');
  1845. if (externalLink != undefined) {
  1846. externalLink.onclick = () => {
  1847. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  1848. let enlace;
  1849. enlace = parametrosURL.get('v');
  1850. window.open(
  1851. `https://www.y2mate.com/es/convert-youtube/${enlace}`,
  1852. 'popUpWindow',
  1853. 'height=800,width=1000,left=50%,top=100,resizable=no,scrollbars=yes,toolbar=no,menubar=yes,location=no,directories=yes, status=no'
  1854. );
  1855. };
  1856. }
  1857. const viewExternalLink = $e('.view_external_link');
  1858. if (viewExternalLink != undefined) {
  1859. viewExternalLink.onclick = () => {
  1860. $e('video').click();
  1861. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  1862. let enlace;
  1863. enlace = parametrosURL.get('v');
  1864. window.open(
  1865. `https://www.youtube.com/embed/${enlace}?rel=0&controls=2&color=white&iv_load_policy=3&showinfo=0&modestbranding=1&autoplay=1`
  1866. );
  1867. };
  1868. }
  1869. const viewPictureToPicture = $e(
  1870. '.video_picture_to_picture'
  1871. );
  1872. if (viewPictureToPicture != undefined) {
  1873. viewPictureToPicture.onclick = () => {
  1874. const video = $e('video');
  1875. // Verifica si el navegador admite Picture-in-Picture
  1876. if ('pictureInPictureEnabled' in document) {
  1877. // Verifica si el video aún no está en modo Picture-in-Picture
  1878. if (!document.pictureInPictureElement) {
  1879. // Intenta activar el modo Picture-in-Picture
  1880. video
  1881. .requestPictureInPicture()
  1882. .then(() => {
  1883. // El video está ahora en modo Picture-in-Picture
  1884. })
  1885. .catch((error) => {
  1886. console.error(
  1887. 'Error al activar el modo Picture-in-Picture:',
  1888. error
  1889. );
  1890. });
  1891. } else {
  1892. // video picture
  1893. }
  1894. } else {
  1895. alert('Picture-in-Picture not supported');
  1896. }
  1897. };
  1898. // Filtro de pantalla
  1899. if (formularioButtons != undefined) {
  1900. formularioButtons.addEventListener('input', function () {
  1901. if (
  1902. $e('#cinematics > div') != undefined ||
  1903. videoFull != undefined
  1904. ) {
  1905. $e('#ojosprotect').style.backgroundColor =
  1906. formularioButtons.value;
  1907. }
  1908. });
  1909. }
  1910. clearInterval(renderizarButtons);
  1911. }
  1912. const checked_updates = $e('.checked_updates');
  1913. if (checked_updates != undefined) {
  1914. checked_updates.onclick = () => {
  1915. window.open(
  1916. `https://update.gf.qytechs.cn/scripts/460680/Youtube%20Tools%20All%20in%20one%20local%20download%20mp3%20mp4%20HIGT%20QUALITY%20return%20dislikes%20and%20more.user.js`
  1917. );
  1918. };
  1919. }
  1920. const screenShotVideo = $e('.screenshot_video');
  1921. if (screenShotVideo != undefined) {
  1922. screenShotVideo.onclick = () => {
  1923. const video = $e('video');
  1924. const canvas = $cl('canvas');
  1925. canvas.width = video.videoWidth;
  1926. canvas.height = video.videoHeight;
  1927. const context = canvas.getContext('2d');
  1928. context.drawImage(video, 0, 0, canvas.width, canvas.height);
  1929. const imagenURL = canvas.toDataURL('image/png');
  1930. const enlaceDescarga = $cl('a');
  1931. enlaceDescarga.href = imagenURL;
  1932. const titleVideo = $e(
  1933. 'h1.style-scope.ytd-watch-metadata'
  1934. ).innerText;
  1935. enlaceDescarga.download = `${video.currentTime.toFixed(
  1936. 0
  1937. )}s_${titleVideo}.png`;
  1938. enlaceDescarga.click();
  1939. };
  1940. } else {
  1941. const containerButtons = $e('.containerButtons');
  1942. if (containerButtons != undefined) {
  1943. containerButtons.innerHTML = '';
  1944. }
  1945. }
  1946. clearInterval(renderizarButtons);
  1947. }
  1948. console.log('Scrip en ejecución by: DeveloperMDCM MDCM');
  1949. const HEADER_STYLE = 'color: #F00; font-size: 24px; font-family: sans-serif;';
  1950. const MESSAGE_STYLE = 'color: #00aaff; font-size: 16px; font-family: sans-serif;';
  1951. const CODE_STYLE = 'font-size: 14px; font-family: monospace;';
  1952. console.log(
  1953. '%cYoutube Tools Extension NEW UI\n' +
  1954. '%cRun %c(v2.2.92)\n' +
  1955. 'By: DeveloperMDCM.',
  1956. HEADER_STYLE,
  1957. CODE_STYLE,
  1958. MESSAGE_STYLE
  1959. );
  1960. // Add event listeners to all inputs
  1961. const inputs = $m('input');
  1962. inputs.forEach((input) => {
  1963. input.addEventListener('change', applySettings);
  1964. if (input.type === 'range') {
  1965. input.addEventListener('change', () => {
  1966. updateSliderValues();
  1967. applySettings();
  1968. });
  1969. }
  1970. });
  1971. // Export configuration
  1972. // Settings saved
  1973. // const settings = GM_getValue('ytSettingsMDCM', '{}');
  1974. // $id('config-data').value = settings;
  1975. $id('export-config').addEventListener('click', () => {
  1976. const settings = GM_getValue('ytSettingsMDCM', '{}');
  1977. $id('config-data').value = settings;
  1978. const configData = settings;
  1979. try {
  1980. JSON.parse(configData); // Validate JSON
  1981. GM_setValue('ytSettingsMDCM', configData);
  1982. alert('Configuration export successfully!');
  1983. } catch (e) {
  1984. alert('Invalid configuration data. Please check and try again.');
  1985. }
  1986. });
  1987. // Import configuration
  1988. $id('import-config').addEventListener('click', () => {
  1989. const configData = $id('config-data').value;
  1990. try {
  1991. JSON.parse(configData); // Validate JSON
  1992. GM_setValue('ytSettingsMDCM', configData);
  1993. alert('Configuration imported successfully!');
  1994. window.location.reload();
  1995. } catch (e) {
  1996. alert('Invalid configuration data. Please check and try again.');
  1997. }
  1998. });
  1999. panel.style.display = 'none'; // Ensure panel is hidden on load
  2000. // Load saved settings
  2001. // Visible element DOM
  2002. function checkElement(selector, callback) {
  2003. const interval = setInterval(() => {
  2004. if ($e(selector)) {
  2005. clearInterval(interval);
  2006. callback();
  2007. }
  2008. }, 100);
  2009. }
  2010. checkElement('ytd-topbar-menu-button-renderer', loadSettings);
  2011. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址