Youtube 工具 多合一本地下載 MP4、MP3

Youtube 工具 多合一本地下載 mp4、MP3

安裝腳本?
作者推薦腳本

您可能也會喜歡 自訂貼紙

安裝腳本
  1. // ==UserScript==
  2. // @name Youtube Tools All in one local download mp3 mp4 HIGT QUALITY return dislikes and more
  3. // @name:zh-TW Youtube 工具 多合一本地下載 MP4、MP3
  4. // @name:zh-HK Youtube 工具 多合一本地下載 MP4、MP3
  5. // @name:zh-CN Youtube 工具 多合一本地下載 MP4、MP3
  6. // @name:ja Youtube ツール オールインワンのローカル ダウンロード MP4、MP3
  7. // @name:kr Youtube 도구 올인원 로컬 다운로드 외부 서비스 없이 MP4, MP3
  8. // @name:ar Youtube Tools All in one local download mp3 mp4 HIGT QUALITY return dislikes and more
  9. // @name:bg Youtube-Tools Alles in einem lokalen Download von MP4, MP3.
  10. // @name:cs Nástroje YouTube Vše v jednom místní Stahujte MP4, MP3
  11. // @name:da Youtube-værktøjer Alt i én lokal Download MP4, MP3
  12. // @name:de Youtube-Tools Alles in einem lokalen Download von MP4, MP3
  13. // @name:tel Youtube టూల్స్ అన్నీ ఒకే లోకల్ డౌన్‌లోడ్ MP4, Mp3
  14. // @name:es Youtube Custom Todo en uno Descarga local MP4, MP3.
  15. // @name:en Youtube Tools All in one local download mp3 mp4.
  16. // @name:fr Outils Youtube Tout-en-un local Téléchargez MP4, MP3.
  17. // @name:fr-CA Outils Youtube Tout-en-un local Téléchargez MP4, MP3.
  18. // @name:he כלים של YouTube הכל במקום אחד מקומי הורדה MP4, MP3 באיכות גבוהה ללא שירות חיצוני ועוד.
  19. // @name:hu Youtube Eszközök Minden egy helyen Letöltés MP4, MP3.
  20. // @name:id Alat Youtube Semua dalam satu lokal Unduh MP4, MP3.
  21. // @name:it Strumenti Youtube Tutto in uno Scarica locale MP4, MP3.
  22. // @name:ko Youtube 도구 올인원 로컬 외부 서비스 없이 MP4, MP3
  23. // @name:nb Youtube-verktøy Alt i ett lokalt Last ned MP4, MP3
  24. // @name:nl Youtube Tools Alles in één lokaal Download MP4, MP3
  25. // @name:pl Narzędzia YouTube Wszystko w jednym lokalnym. Pobierz MP4, MP3
  26. // @name:pt-BR Ferramentas do Youtube Tudo em um local Baixe MP4, MP3 DE ALTA QUALIDAD.
  27. // @name:ro YInstrumente Youtube Toate într-un singur local Descărcați MP4, MP3.
  28. // @name:ru Инструменты Youtube Все в одном локальном формате. Загрузите MP4, MP3.
  29. // @name:sk Nástroje YouTube Všetko v jednom miestne Stiahnite si MP4, MP3
  30. // @name:sr Иоутубе алати Све у једном локалном Преузми МП4, МП3
  31. // @name:sv Youtube-verktyg Allt i ett lokalt Ladda ner MP4, MP3
  32. // @name:th เครื่องมือ Youtube ทั้งหมดในที่เดียว ดาวน์โหลด MP4, MP3
  33. // @name:tr Youtube Araçları Hepsi bir arada yerel Harici hizmet olmadan MP4, MP3
  34. // @name:uk Інструменти Youtube Все в одному локальному завантаженні MP4, MP3
  35. // @name:ug Youtube قوراللىرى ھەممىسى بىر يەرلىك چۈشۈرۈش MP4,mp3
  36. // @name:vi Công cụ Youtube Tất cả trong một cục bộ Tải xuống MP4, MP3
  37. // @description:zh-TW Youtube 工具 多合一本地下載 mp4、MP3
  38. // @description:zh-HK Youtube 工具 多合一本地下載 mp4、MP3
  39. // @description:zh-CN Youtube 工具 多合一本地下載 mp4、MP3
  40. // @description:ja Youtube ツール オールインワン ローカル ダウンロード mp4、MP3 、
  41. // @description:kr Youtube 도구 올인원 로컬 다운로드 mp4, MP3
  42. // @description:ar Herramientas de YouTube Todo en uno Descarga local mp4, MP3
  43. // @description:bg Инструменти за Youtube Всичко в едно локално изтегляне mp4,
  44. // @description:cs Nástroje YouTube Vše v jednom místní Stahování mp4, MP3
  45. // @description:da Youtube-værktøjer Alt i ét lokalt Download mp4, MP3
  46. // @description:de YouTube-Tools Alles in einem lokalen Laden Sie MP4, MP3
  47. // @description:tel Youtube Tools All in one local Download mp4, MP3 HIGT QUALITY,
  48. // @description:es Youtube tools todo en uno personlizada youtube a tu estilo y descarga MP4 y MP3
  49. // @description:fr Outils Youtube Tout-en-un local Téléchargez des mp4, des MP3
  50. // @description:fr-CA Outils Youtube Tout-en-un local Téléchargez des mp4, des MP3
  51. // @description:he כלים של YouTube הכל במקום אחד מקומי הורד mp4, MP3
  52. // @description:hu Youtube Eszközök Minden egyben helyi Letöltés mp4, MP3
  53. // @description:id Alat Youtube Semua dalam satu lokal Unduh mp4, MP3
  54. // @description:it Strumenti Youtube Tutto in uno locale Scarica mp4, MP3
  55. // @description:ko Youtube 도구 올인원 로컬 다운로드 mp4, MP3
  56. // @description:nb YoYoutube-verktøy Alt i ett lokalt Last ned mp4, MP3
  57. // @description:nl YouTube-tools Alles in één lokaal Download mp4, MP3
  58. // @description:pl Narzędzia Youtube Wszystko w jednym miejscu Pobierz mp4, MP3
  59. // @description:pt-BR Ferramentas do YouTube Tudo em um só local Baixe mp4, MP3
  60. // @description:ro Instrumente Youtube Toate într-un singur local Descărcați mp4, MP3
  61. // @description:ru Инструменты Youtube Все в одном, локально. Загрузите mp4, MP3
  62. // @description:sk Nástroje YouTube Všetko v jednom miestnom Sťahujte mp4, MP3
  63. // @description:sr Иоутубе алати Све у једном локалном Преузми мп4, МП3
  64. // @description:sv Youtube-verktyg Allt i ett lokalt Ladda ner mp4, MP3
  65. // @description:th เครื่องมือ Youtube ทั้งหมดในที่เดียว ดาวน์โหลด mp4, MP3
  66. // @description:tr Youtube Araçları Hepsi bir arada yerel Harici hizmet olmadan mp4, MP3
  67. // @description:uk Інструменти Youtube Все в одному локальному завантаженні mp4, MP3
  68. // @description:ug Youtube قورالىنىڭ ھەممىسى بىر يەرلىك چۈشۈرۈشتە mp4, MP3 HIGH QUAقنى قا
  69. // @description:vi Công cụ Youtube Tất cả trong một cục bộ Tải xuống mp4, MP3
  70. // @description:en Youtube Tools All in one local Download mp4, MP3 HIGT QUALITY
  71. // @description Youtube Tools All in one local Download mp4, MP3 HIGT QUALITY
  72. // @homepage https://github.com/DeveloperMDCM/
  73. // @version 2.3.3.2
  74. // @author DeveloperMDCM
  75. // @match *://www.youtube.com/*
  76. // @exclude *://music.youtube.com/*
  77. // @exclude *://*.music.youtube.com/*
  78. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  79. // @grant GM_info
  80. // @grant GM_addStyle
  81. // @grant GM_setValue
  82. // @grant GM_getValue
  83. // @grant unsafeWindow
  84. // @run-at document-end
  85. // @compatible chrome
  86. // @compatible firefox
  87. // @compatible opera
  88. // @compatible safari
  89. // @compatible edge
  90. // @license MIT
  91. // @namespace https://github.com/DeveloperMDCM/
  92. // ==/UserScript==
  93.  
  94. (function () {
  95. 'use strict';
  96. let validoUrl = document.location.href;
  97. const $e = (el) => document.querySelector(el); // any element
  98. const $id = (el) => document.getElementById(el); // element by id
  99. const $m = (el) => document.querySelectorAll(el); // multiple all elements
  100. const $cl = (el) => document.createElement(el); // create element
  101. const $sp = (el, pty) => document.documentElement.style.setProperty(el, pty); // set property variable css
  102. const $ap = (el) => document.body.appendChild(el); // append element
  103. const apiDislikes = "https://returnyoutubedislikeapi.com/Votes?videoId="; // Api dislikes
  104. const UPDATE_INTERVAL = 1000;
  105. const STORAGE = {
  106. USAGE: 'YT_TOTAL_USAGE',
  107. VIDEO: 'YT_VIDEO_TIME',
  108. SHORTS: 'YT_SHORTS_TIME'
  109. };
  110.  
  111. let usageTime = GM_getValue(STORAGE.USAGE, 0);
  112. let videoTime = GM_getValue(STORAGE.VIDEO, 0);
  113. let shortsTime = GM_getValue(STORAGE.SHORTS, 0);
  114. let lastUpdate = Date.now();
  115. let activeVideo = null;
  116. let activeType = null;
  117.  
  118. // Inicializar almacenamiento
  119. GM_setValue(STORAGE.USAGE, usageTime);
  120. GM_setValue(STORAGE.VIDEO, videoTime);
  121. GM_setValue(STORAGE.SHORTS, shortsTime);
  122.  
  123. function FormatterNumber(num, digits) {
  124. const lookup = [
  125. {
  126. value: 1,
  127. symbol: '',
  128. },
  129. {
  130. value: 1e3,
  131. symbol: ' K',
  132. },
  133. {
  134. value: 1e6,
  135. symbol: ' M',
  136. },
  137. ];
  138. const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
  139. const item = lookup
  140. .slice()
  141. .reverse()
  142. .find((item) => {
  143. return num >= item.value;
  144. });
  145. return item
  146. ? (num / item.value).toFixed(digits).replace(rx, '$1') + item.symbol
  147. : '0';
  148. }
  149.  
  150. function paramsVideoURL() {
  151. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  152. return parametrosURL.get('v');
  153. }
  154.  
  155. // Dislikes video
  156. async function videoDislike() {
  157.  
  158. validoUrl = document.location.href;
  159.  
  160. const validoVentana = $e('#below > ytd-watch-metadata > div');
  161. if (validoVentana != undefined && document.location.href.split('?v=')[0].includes('youtube.com/watch')) {
  162. validoUrl = paramsVideoURL();
  163. const urlShorts = `${apiDislikes}${validoUrl}`;
  164. try {
  165. const respuesta = await fetch(urlShorts);
  166. const datosShort = await respuesta.json();
  167. const { dislikes } = datosShort;
  168. 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');
  169. if (dislikes_content !== undefined) {
  170. dislikes_content.style = 'width: 90px';
  171. dislikes_content.innerHTML = `
  172. <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>
  173. ${FormatterNumber(dislikes, 0)}`;
  174. }
  175.  
  176. } catch (error) {
  177. console.log(error);
  178. }
  179. }
  180. }
  181.  
  182. // dislikes shorts
  183. async function shortDislike() {
  184. validoUrl = document.location.href;
  185. const validoVentanaShort = $m(
  186. '#dislike-button > yt-button-shape > label > div > span'
  187. );
  188. if (validoVentanaShort != undefined && document.location.href.split('/')[3] === 'shorts') {
  189. validoUrl = document.location.href.split('/')[4];
  190. const urlShorts = `${apiDislikes}${validoUrl}`;
  191. try {
  192. const respuesta = await fetch(urlShorts);
  193. const datosShort = await respuesta.json();
  194. const { dislikes } = datosShort;
  195. for (let i = 0; i < validoVentanaShort.length; i++) {
  196. validoVentanaShort[i].textContent = `${FormatterNumber(
  197. dislikes,
  198. 0
  199. )}`;
  200. }
  201. } catch (error) {
  202. console.log(error);
  203. }
  204. }
  205. }
  206.  
  207. // Url change in second load
  208. let prevUrl;
  209. let showDislikes = false;
  210.  
  211. setInterval(() => {
  212. const svgDislike = $e('.svg-dislike-ico'); // Check svg in dom
  213. const currUrl = window.location.href;
  214. if (prevUrl !== undefined && currUrl !== prevUrl && !svgDislike && showDislikes) {
  215. setTimeout(async() => {
  216. await videoDislike();
  217. await shortDislike();
  218. },2000)
  219. }
  220. prevUrl = currUrl;
  221. }, 1000);
  222.  
  223.  
  224.  
  225. // Create a Trusted Types policy
  226. const policy = window.trustedTypes?.createPolicy('default', {
  227. createHTML: (input) => input,
  228. });
  229.  
  230.  
  231. // Styles for our enhancement panel
  232. GM_addStyle(`
  233. #yt-stats {
  234. position: fixed;
  235. top: 60px;
  236. right: 20px;
  237. background: #1a1a1a;
  238. color: white;
  239. padding: 15px;
  240. border-radius: 10px;
  241. width: 320px;
  242. box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  243. font-family: Arial, sans-serif;
  244. display: none;
  245. }
  246. #yt-stats-toggle {
  247. font-size: 12px;
  248. background: #1e1b1b;
  249. color: #fff;
  250. padding: 12px 20px;
  251. border-radius: 5px;
  252. cursor: pointer;
  253. box-shadow: 0 2px 6px rgba(0,0,0,0.3);
  254. }
  255. .stat-row {
  256. margin: 15px 0;
  257. }
  258. .progress {
  259. height: 6px;
  260. background: #333;
  261. border-radius: 3px;
  262. margin: 8px 0;
  263. }
  264. .progress-bar {
  265. height: 100%;
  266. transition: width 0.3s;
  267. }
  268. .total-bar { background: #44aaff; }
  269. .video-bar { background: #00ff88; }
  270. .shorts-bar { background: #ff4444; }
  271. #cinematics {
  272. position: absolute !important;
  273. width: 90vw !important;
  274. height: 100vh ;
  275. }
  276. #cinematics div {
  277. position: fixed;
  278. inset: 0px;
  279. pointer-events: none;
  280. transform: scale(1.5, 2);
  281. }
  282. #cinematics > div > div > canvas:nth-child(1), #cinematics > div > div > canvas:nth-child(2) {
  283. position: absolute !important;
  284. width: 90vw !important;
  285. height: 100vh ;
  286. }
  287.  
  288. // .html5-video-player.unstarted-mode {
  289. // background-image: url('https://avatars.githubusercontent.com/u/54366580?v=4');
  290. // background-repeat: no-repeat;
  291. // background-position: 50% 50%;
  292. // display: flex;
  293. // justify-content: center;
  294. // align-items: center;
  295. // }
  296.  
  297. #yt-enhancement-panel {
  298. position: fixed;
  299. top: 60px;
  300. right: 20px;
  301. background-color: var(--yt-enhance-menu-bg, #ffffff);
  302. color: var(--yt-enhance-menu-text, #000000);
  303. border: 1px solid #cccccc;
  304. border-radius: 8px;
  305. padding: 15px;
  306. z-index: 9999;
  307. box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  308. width: 300px;
  309. max-height: 80vh;
  310. overflow-y: auto;
  311. font-size: var(--yt-enhance-menu-font-size, 14px);
  312. }
  313. #yt-enhancement-panel h3 {
  314. margin-top: 0;
  315. color: #ff0000;
  316. }
  317. .enhancement-option {
  318. margin-bottom: 10px;
  319. }
  320. .color-picker {
  321. width: 100%;
  322. margin: 0;
  323. padding: 0;
  324. border: none;
  325. background: none;
  326. }
  327. .slider {
  328. width: 100%;
  329. }
  330. #toggle-panel {
  331. z-index: 10000;
  332. color: white;
  333. padding: 5px;
  334. border: none;
  335. cursor: pointer;
  336. display: flex;
  337. justify-content: center;
  338. transition: all 0.5s ease;
  339. width: 43px;
  340. border-radius: 100px;
  341. }
  342. #toggle-button:hover {
  343. background-color: rgba(255,255,255,0.1);
  344. border-radius: 50%;
  345. opacity: 1 !important;
  346. }
  347. #icon-menu-settings {
  348. width: 24px;
  349. height: 24px;
  350. padding: 7px;
  351. margin-right: 5px;
  352. cursor: pointer;
  353. user-select: none;
  354. }
  355.  
  356. .tab-buttons {
  357. display: flex;
  358. justify-content: space-between;
  359. gap: 10px;
  360. margin-bottom: 15px;
  361. }
  362. .tab-button {
  363. background-color: #f0f0f0;
  364. border: none;
  365. width: 100%;
  366. padding: 5px 10px;
  367. cursor: pointer;
  368. border-radius: 4px;
  369. }
  370. .tab-button.active {
  371. background-color: #ff0000;
  372. color: white;
  373. }
  374. .tab-button-active {
  375. background-color: #ff0000;
  376. color: white;
  377. border: none;
  378. border-radius: 2px;
  379. }
  380. .tab-content {
  381. display: none;
  382. }
  383. .tab-content.active {
  384. display: block;
  385. }
  386. #import-export {
  387. margin-top: 15px;
  388. }
  389. #import-export textarea {
  390. width: 100%;
  391. height: 100px;
  392. }
  393. #menu-settings-icon {
  394. cursor: pointer;
  395. float: right;
  396. font-size: 20px;
  397. }
  398. .theme-option {
  399. margin-bottom: 15px;
  400. }
  401. .theme-option label {
  402. display: flex;
  403. align-items: center;
  404. }
  405. .theme-option {
  406. position: relative;
  407. width: auto;
  408. margin-bottom: 10px;
  409. padding: 10px;
  410. border-radius: 4px;
  411. cursor: pointer;
  412. }
  413.  
  414. .theme-preview {
  415. position: absolute;
  416. top: 0;
  417. left: 0;
  418. right: 0;
  419. bottom: 0;
  420. border-radius: 10px;
  421. border: 1px solid #000;
  422. z-index: 1;
  423. }
  424.  
  425. .theme-option input[type="radio"] {
  426. position: relative;
  427. z-index: 2;
  428. margin-right: 10px;
  429. cursor: pointer;
  430. }
  431.  
  432. .theme-name {
  433. position: relative;
  434. z-index: 2;
  435. font-size: 15px;
  436. color: #fff;
  437. }
  438.  
  439. .theme-option label {
  440. display: flex;
  441. align-items: center;
  442. width: 100%;
  443. position: relative;
  444. z-index: 2;
  445. }
  446.  
  447. .buttons-tranlate {
  448. background: #000;
  449. font-size: 10px;
  450. border: none;
  451. color: #fbf4f4 !important;
  452. padding: 3px 0;
  453. margin-left: 10px;
  454. width: 70px;
  455. border-radius: 10px;}
  456. .buttons-tranlate:hover {
  457. cursor: pointer;
  458. background-color: #6b6b6b;}
  459.  
  460. button.botones_div {
  461. margin: 0;
  462. padding: 0;
  463.  
  464. }
  465.  
  466. .tab-button:hover {
  467. background-color: #ec3203 !important;
  468. color: #ffffff !important;
  469. cursor: pointer;
  470. }
  471.  
  472. #eyes {
  473. opacity: 0;
  474. position: absolute;
  475. height: 24px;
  476. left: 0;
  477. width: 24px;
  478. }
  479.  
  480. /* width */
  481. ::-webkit-scrollbar {
  482. width: 4px;
  483. height: 10px;
  484. }
  485.  
  486. /* Track */
  487. ::-webkit-scrollbar-track {
  488. background: ##d5d5d5;
  489.  
  490. }
  491.  
  492. /* Handle */
  493. ::-webkit-scrollbar-thumb {
  494. background: #000;
  495.  
  496. }
  497.  
  498. .containerButtons {
  499. display: flex;
  500. justify-content: center;
  501. align-items: center;
  502. flex-wrap: wrap;
  503. gap: 10px;
  504. }
  505. .containerButtons > button:hover {
  506. cursor: pointer;
  507. }
  508.  
  509. body {
  510. padding: 0;
  511. margin: 0;
  512. overflow-y: scroll;
  513. overflow-x: hidden;
  514. }
  515. .style-scope.ytd-comments {
  516. overflow-y: auto;
  517. overflow-x: hidden;
  518. height: auto;
  519. }
  520. ytd-comment-view-model[is-reply] #author-thumbnail.ytd-comment-view-model yt-img-shadow.ytd-comment-view-model, ytd-comment-view-model[is-creator-reply] #author-thumbnail.ytd-comment-view-model yt-img-shadow.ytd-comment-view-model {
  521. width: 40px;
  522. height: 40px;
  523. border-radius: 50%;
  524. }
  525. img.yt-img-shadow {
  526. border-radius: 50% !important;
  527. }
  528. #author-thumbnail.ytd-comment-view-model yt-img-shadow.ytd-comment-view-model {
  529. width: 40px;
  530. height: 40px;
  531. border-radius: 50%;
  532. overflow: visible;
  533. }
  534. ytd-item-section-renderer.ytd-watch-next-secondary-results-renderer {
  535. --ytd-item-section-item-margin: 8px;
  536. overflow-y: auto;
  537. overflow-x: hidden;
  538. height: auto;
  539. }
  540. .right-section.ytcp-header {
  541. display: flex;
  542. flex: 1;
  543. align-items: center;
  544. gap: 45px;
  545. justify-content: end;
  546. }
  547. #meta.ytd-playlist-panel-video-renderer {
  548. min-width: 0;
  549. padding: 0 8px;
  550. display: flexbox;
  551. display: flex;
  552. flex-direction: column-reverse;
  553. flex: 1;
  554. flex-basis: 0.000000001px;
  555. }
  556.  
  557. .containerall {
  558. display: flex;
  559. align-items: center;
  560. justify-content: center;
  561. width: 50%;
  562. margin: auto;
  563. }
  564. }
  565. .container .botoncalidades {
  566. margin: 3px 2px;
  567. width: 24.6%;
  568. }
  569.  
  570. .botoncalidades:first-child {
  571. background-color: #0af;
  572. }
  573.  
  574. .botoncalidades:last-child {
  575. background-color: red;
  576. width: 100px;
  577. }
  578.  
  579. .selectcalidades,
  580. .botoncalidades,
  581. .selectcalidadesaudio {
  582. width: 50%;
  583. height: 27.8px;
  584. background-color: #fff;
  585. color: #000;
  586. font-size: 25px;
  587. text-align: center;
  588. border: none;
  589. font-size: 20px;
  590. margin: 2px 2px;
  591. }
  592.  
  593. .botoncalidades {
  594. width: 70px;
  595. height: 30px;
  596. background-color: rgb(4, 156, 22);
  597. border: 0px solid #000;
  598. color: #fff;
  599. font-size: 20px;
  600. border-radius: 10px;
  601. margin: 2px 2px;
  602. }
  603.  
  604. .botoncalidades:hover,
  605. .bntcontainer:hover {
  606. cursor: pointer;
  607. }
  608.  
  609. .ocultarframe,
  610. .ocultarframeaudio {
  611. display: none;
  612. }
  613. .checked_updates {
  614. cursor: pointer;
  615. }
  616.  
  617. #export-config, #import-config {
  618. width: 100%;
  619. display: flex;
  620. align-items: center;
  621. justify-content: center;
  622. gap: 10px;
  623. background-color: #ec3203;
  624. color: #ffffff;
  625. border: none;
  626. padding: 5px;
  627. }
  628. #export-config:hover, #import-config:hover {
  629. background-color: #ff0000;
  630. color: #ffffff;
  631. cursor: pointer;
  632. }
  633.  
  634. .yt-image-avatar-download {
  635. position: absolute;
  636. bottom: -10px;
  637. right: -14px;
  638. border: none;
  639. z-index: 1000;
  640. background: transparent;
  641. color: var(--ytcp-text-primary);
  642. cursor: pointer;
  643. }
  644.  
  645. .custom-classic-btn {
  646. display: flex;
  647. align-items: center;
  648. justify-content: center;
  649. background-color: rgba(255,255,255,0.1);
  650. border-radius: 50%;
  651. border: none;
  652. width: 48px;
  653. height: 48px;
  654. color: var(--yt-spec-icon-inactive);
  655. font-size: 24px;
  656. margin: 0px 8px;
  657. cursor: pointer;
  658. }
  659. .custom-classic-btn:hover {
  660. background-color: rgba(255,255,255,0.2);
  661. }
  662. `);
  663.  
  664.  
  665. // botons bottom video player
  666.  
  667. const thumbnailVideo = `
  668. <button title="Image video" class="botones_div" type="button" id="imagen">
  669.  
  670. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-photo-down" width="24"
  671. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  672. stroke-linecap="round" stroke-linejoin="round">
  673. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  674. <path d="M15 8h.01"></path>
  675. <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>
  676. <path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l4 4"></path>
  677. <path d="M14 14l1 -1c.653 -.629 1.413 -.815 2.13 -.559"></path>
  678. <path d="M19 16v6"></path>
  679. <path d="M22 19l-3 3l-3 -3"></path>
  680. </svg>
  681. </button>
  682. `;
  683.  
  684.  
  685. const filterEyes = `
  686.  
  687. <div style="position:relative; ">
  688. <button title="Filter eyes" class="botones_div" type="button">
  689. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brightness-half"
  690. width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"
  691. fill="none" stroke-linecap="round" stroke-linejoin="round">
  692. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  693. <path d="M12 9a3 3 0 0 0 0 6v-6z"></path>
  694. <path
  695. 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">
  696. </path>
  697. </svg>
  698. <input id="eyes" list="presetColors" type="color" value="#ffffff">
  699. <datalist id="presetColors">
  700. <option value="#000000" />
  701. <option value="#fbff00" />
  702. <option value="#ff0000" />
  703. <option value="#00ff00" />
  704. <option value="#0000ff" />
  705. </datalist>
  706. <div id="ojosprotect"
  707. style="position: fixed; pointer-events: none; width: 100%; height: 100%; left: 0px; top: 0px; opacity: 0.2; z-index: 10; display: block;">
  708. </div>
  709. </div>
  710. </button>
  711. `;
  712.  
  713. const resetButton = `
  714. <button title="reset" class="botones_div" type="button" id="reset_button">
  715. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-power" width="24"
  716. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  717. stroke-linecap="round" stroke-linejoin="round">
  718. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  719. <path d="M7 6a7.75 7.75 0 1 0 10 0"></path>
  720. <path d="M12 4l0 8"></path>
  721. </svg>
  722. </button>
  723. `;
  724.  
  725. const repeatVideo = `
  726. <button title="Repeat video" class="botones_div" type="button" id="repeatvideo">
  727.  
  728. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-repeat" width="24"
  729. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  730. stroke-linecap="round" stroke-linejoin="round">
  731. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  732. <path d="M4 12v-3a3 3 0 0 1 3 -3h13m-3 -3l3 3l-3 3"></path>
  733. <path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path>
  734. </svg>
  735. </button>
  736. `;
  737.  
  738. const downloadMp4Mp3 = `
  739. <button title="MP4" type="button" class="btn1 botones_div">
  740. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-download"
  741. width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  742. stroke-linecap="round" stroke-linejoin="round">
  743. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  744. <path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
  745. <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>
  746. <path d="M12 17v-6"></path>
  747. <path d="M9.5 14.5l2.5 2.5l2.5 -2.5"></path>
  748. </svg>
  749. </button>
  750. <button title="MP3" type="button" class="btn2 botones_div">
  751.  
  752. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-music" width="24"
  753. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  754. stroke-linecap="round" stroke-linejoin="round">
  755. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  756. <path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
  757. <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>
  758. <path d="M11 16m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
  759. <path d="M12 16l0 -5l2 1"></path>
  760. </svg>
  761. </button>
  762. <button title="Close" type="button" class="btn3 botones_div">
  763. <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="24"
  764. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  765. stroke-linecap="round" stroke-linejoin="round">
  766. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  767. <path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
  768. <path d="M10 10l4 4m0 -4l-4 4"></path>
  769. </svg>
  770. </button>
  771. `;
  772.  
  773. const donwloadExternal = `
  774.  
  775. <button title="External Download" type="button" class="external_link botones_div">
  776.  
  777. <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">
  778. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  779. <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>
  780. <path d="M11 13l9 -9"></path>
  781. <path d="M15 4h5v5"></path>
  782. </svg>
  783. </button>
  784.  
  785. `;
  786. const viewExternalVideo = `
  787.  
  788. <button title="view External no cookie" type="button" class="view_external_link botones_div">
  789.  
  790. <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>
  791. </button>
  792.  
  793. `;
  794.  
  795. const pictureToPicture = `
  796. <button title="Picture to picture" type="button" class="video_picture_to_picture botones_div">
  797.  
  798. <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>
  799. </button>
  800.  
  801. `;
  802. const screenShot = `
  803. <button title="Screenshot video" type="button" class="screenshot_video botones_div">
  804. <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>
  805. </button>
  806.  
  807. `;
  808.  
  809. const checkUpdates = `
  810. <button title="Check new updates" type="button" class="checked_updates botones_div">
  811. <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>
  812. </button>
  813. `;
  814.  
  815. const bufferVideo = `
  816. <button title="Buffer video" type="button" class="buffer_video botones_div">
  817. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-align-box-right-stretch"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 17h2" /><path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z" /><path d="M11 12h6" /><path d="M13 7h4" /></svg>
  818. </button>
  819. `;
  820.  
  821.  
  822. const menuBotones = `
  823. <main>
  824. <div class="container">
  825. <form>
  826. <div class="containerButtons">
  827. ${thumbnailVideo}
  828. ${bufferVideo}
  829. ${filterEyes}
  830. ${resetButton}
  831. ${repeatVideo}
  832. ${downloadMp4Mp3}
  833. ${donwloadExternal}
  834. ${viewExternalVideo}
  835. ${pictureToPicture}
  836. ${screenShot}
  837. ${checkUpdates}
  838. </div>
  839. <div>
  840. </div>
  841. </form>
  842.  
  843. </div>
  844. <div class="content_collapsible_colors" style="margin-top: 10px">
  845.  
  846. <form class="formulariodescarga" action="">
  847. <div class="containerall">
  848. <select class="selectcalidades ocultarframe" required>
  849. <option selected disabled>Calidad del video / Quality video</option>
  850. <option value="360">360p Mp4</option>
  851. <option value="480">480p Mp4</option>
  852. <option value="720">720p HD Mp4 Default</option>
  853. <option value="1080">1080p FULL HD Mp4</option>
  854. <option value="4k">2160p 4K WEBM</option>
  855. <option value="8k">4320p 8K WEBM</option>
  856. </select>
  857. <iframe id="descargando" style="z-index: 99; border: none; height: 27.4px; width: 50%;" class="containerall ocultarframe" src="" frameborder="0"></iframe>
  858.  
  859. </div>
  860. </form>
  861. <form class="formulariodescargaaudio" action="">
  862. <div class="containerall">
  863. <select class="selectcalidadesaudio ocultarframeaudio" required>
  864. <option selected disabled>Calidad del Audio / Quality Audio</option>
  865. <option value="flac">Audio FLAC UHQ</option>
  866. <option value="wav">Audio WAV UHQ</option>
  867. <option value="mp3">Audio MP3 Default</option>
  868. <option value="m4a">Audio M4A</option>
  869. <option value="aac">Audio AAC</option>
  870. <option value="opus">Audio OPUS</option>
  871. <option value="ogg">Audio OGG</option>
  872. </select>
  873. <iframe id="descargandomp3" style="z-index: 99; border: none; height: 27.4px; width: 50%;" class="containerall ocultarframeaudio" src="" frameborder="0"></iframe>
  874.  
  875. </iframe>
  876.  
  877. </div>
  878. </form>
  879. </main>
  880. </html>
  881. `;
  882.  
  883.  
  884.  
  885. // Define themes
  886. const themes = [
  887. {
  888. name: 'Default / Reload Page',
  889. gradient: '',
  890. textColor: '',
  891. raised: '',
  892. btnTranslate: '',
  893. CurrentProgressVideo: '',
  894. videoDuration: '',
  895. colorIcons: '',
  896. textLogo: '',
  897. primaryColor: '',
  898. secondaryColor: '',
  899. },
  900. {
  901. name: 'Midnight Blue',
  902. gradient: 'linear-gradient(135deg, #1e3a8a, #3b82f6)',
  903. textColor: '#ffffff',
  904. raised: '#f00',
  905. btnTranslate: '#000',
  906. CurrentProgressVideo: '#0f0',
  907. videoDuration: '#fff',
  908. colorIcons: '#fff',
  909. textLogo: '#f00',
  910. },
  911. {
  912. name: 'Forest Green',
  913. gradient: 'linear-gradient(135deg, #14532d, #22c55e)',
  914. textColor: '#ffffff',
  915. raised: '#303131',
  916. btnTranslate: '#000',
  917. CurrentProgressVideo: '#0f0',
  918. videoDuration: '#fff',
  919. colorIcons: '#fff',
  920. textLogo: '#f00',
  921. },
  922. {
  923. name: 'Sunset Orange',
  924. gradient: 'linear-gradient(135deg, #7c2d12, #f97316)',
  925. textColor: '#ffffff',
  926. raised: '#303131',
  927. btnTranslate: '#000',
  928. CurrentProgressVideo: '#0f0',
  929. videoDuration: '#fff',
  930. colorIcons: '#fff',
  931. textLogo: '#f00',
  932. },
  933. {
  934. name: 'Royal Purple',
  935. gradient: 'linear-gradient(135deg, #4c1d95, #8b5cf6)',
  936. textColor: '#ffffff',
  937. raised: '#303131',
  938. btnTranslate: '#000',
  939. CurrentProgressVideo: '#0f0',
  940. videoDuration: '#fff',
  941. colorIcons: '#fff',
  942. textLogo: '#f00',
  943. },
  944. {
  945. name: 'Cherry Blossom',
  946. gradient: 'linear-gradient(135deg, #a9005c, #fc008f)',
  947. textColor: '#ffffff',
  948. raised: '#fc008f',
  949. btnTranslate: '#000',
  950. CurrentProgressVideo: '#0f0',
  951. videoDuration: '#fff',
  952. colorIcons: '#fff',
  953. textLogo: '#f00',
  954. },
  955. {
  956. name: 'Red Dark',
  957. gradient: 'linear-gradient(135deg, #790909, #f70131)',
  958. textColor: '#ffffff',
  959. raised: '#303131',
  960. btnTranslate: '#000',
  961. CurrentProgressVideo: '#0f0',
  962. videoDuration: '#fff',
  963. colorIcons: '#fff',
  964. textLogo: '#f00',
  965. },
  966. {
  967. name: 'Raind ',
  968. gradient: 'linear-gradient(90deg, #3f5efb 0%, #fc466b) 100%',
  969. textColor: '#ffffff',
  970. raised: '#303131',
  971. btnTranslate: '#000',
  972. CurrentProgressVideo: '#0f0',
  973. videoDuration: '#fff',
  974. colorIcons: '#fff',
  975. textLogo: '#f00',
  976. },
  977. {
  978. name: 'Neon',
  979. gradient: 'linear-gradient(273deg, #ee49fd 0%, #6175ff 100%)',
  980. textColor: '#ffffff',
  981. raised: '#303131',
  982. btnTranslate: '#000',
  983. CurrentProgressVideo: '#0f0',
  984. videoDuration: '#fff',
  985. colorIcons: '#fff',
  986. textLogo: '#f00',
  987. },
  988. {
  989. name: 'Azure',
  990. gradient: 'linear-gradient(273deg, #0172af 0%, #74febd 100%)',
  991. textColor: '#ffffff',
  992. raised: '#303131',
  993. btnTranslate: '#000',
  994. CurrentProgressVideo: '#0f0',
  995. videoDuration: '#fff',
  996. colorIcons: '#fff',
  997. textLogo: '#f00',
  998. },
  999. {
  1000. name: 'Butterfly',
  1001. gradient: 'linear-gradient(273deg, #ff4060 0%, #fff16a 100%)',
  1002. textColor: '#ffffff',
  1003. raised: '#303131',
  1004. btnTranslate: '#000',
  1005. CurrentProgressVideo: '#0f0',
  1006. videoDuration: '#fff',
  1007. colorIcons: '#fff',
  1008. textLogo: '#f00',
  1009. },
  1010. {
  1011. name: 'Colombia',
  1012. gradient:
  1013. 'linear-gradient(174deg, #fbf63f 0%, #0000bb 45%, #ff0000 99%)',
  1014. textColor: '#ffffff',
  1015. raised: '#303131',
  1016. btnTranslate: '#000',
  1017. CurrentProgressVideo: '#0f0',
  1018. videoDuration: '#fff',
  1019. colorIcons: '#fff',
  1020. textLogo: '#f00',
  1021. },
  1022. ];
  1023.  
  1024. // Create our enhancement panel
  1025. const panel = $cl('div');
  1026.  
  1027. panel.id = 'yt-enhancement-panel';
  1028.  
  1029. // Generate theme options HTML
  1030. const themeOptionsHTML = themes
  1031. .map(
  1032. (theme, index) => `
  1033. <label >
  1034. <div class="theme-option">
  1035. <div class="theme-preview" style="background: ${theme.gradient};"></div>
  1036. <input type="radio" name="theme" value="${index}" ${
  1037. index === 0 ? 'checked' : ''
  1038. }>
  1039. <span style="${theme.name === 'Default / Reload Page' ? 'color: red; ' : '' }" class="theme-name">${theme.name}</span>
  1040. </div>
  1041. </label>
  1042. `
  1043. )
  1044. .join('');
  1045.  
  1046. // find atribute dark in dom
  1047. const htmlElement = $e('html');
  1048. const isDarkMode = htmlElement.hasAttribute('dark');
  1049. let isDarkModeActive = isDarkMode;
  1050.  
  1051.  
  1052. // Use Trusted Types to set innerHTML
  1053. const panelHTML = policy
  1054. ? policy.createHTML(`
  1055. <div style="display: flex;justify-content: space-between;align-items: center;gap: 3px;margin-bottom: 10px;">
  1056. <h4 style="display: flex;align-items: center;gap: 10px;">YouTube Tools v2.3.3.2 <a target="_blank" href="https://github.com/DeveloperMDCM/Youtube-tools-extension">
  1057. <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>
  1058. </a></h4>
  1059. <div style="display: flex; gap: 5px;">
  1060. <span id="menu-settings-icon">⚙️</span>
  1061. <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>
  1062. <span style="cursor: pointer" class="close_menu_settings">❎</span>
  1063. </div>
  1064. </div>
  1065. <div class="tab-buttons">
  1066. <button class="tab-button active" data-tab="general">General</button>
  1067. <button class="tab-button" data-tab="themes">Themes</button>
  1068. <button class="tab-button" data-tab="stats">Stats</button>
  1069. <button class="tab-button" data-tab="headers">Header</button>
  1070. </div>
  1071. <div id="general" class="tab-content active">
  1072. <div class="enhancement-option">
  1073. <label>
  1074. <input type="checkbox" id="hide-comments-toggle"> Hide Comments
  1075. </label>
  1076. </div>
  1077. <div class="enhancement-option">
  1078. <label>
  1079. <input type="checkbox" id="hide-sidebar-toggle"> Hide Sidebar
  1080. </label>
  1081. </div>
  1082. <div class="enhancement-option">
  1083. <label>
  1084. <input type="checkbox" id="autoplay-toggle"> Disable Autoplay
  1085. </label>
  1086. </div>
  1087. <div class="enhancement-option">
  1088. <label>
  1089. <input type="checkbox" id="subtitles-toggle"> Disable Subtitles
  1090. </label>
  1091. </div>
  1092. <div class="enhancement-option">
  1093. <label>
  1094. <input type="checkbox" id="dislikes-toggle"> Show Dislikes / Reload page
  1095. </label>
  1096. </div>
  1097. <div class="enhancement-option">
  1098. <label>
  1099. <input type="checkbox" id="themes-toggle"> Active Themes / Reload page
  1100. </label>
  1101. </div>
  1102. <div class="enhancement-option">
  1103. <label>
  1104. <input type="checkbox" id="translation-toggle"> Translate comments / Reload page
  1105. </label>
  1106. </div>
  1107. <div class="enhancement-option">
  1108. <label>
  1109. <input type="checkbox" id="avatars-toggle"> Download avatars / Reload page
  1110. </label>
  1111. </div>
  1112. <div class="enhancement-option">
  1113. <label>
  1114. <input type="checkbox" id="reverse-mode-toggle"> Reverse mode
  1115. </label>
  1116. </div>
  1117.  
  1118. <div class="enhancement-option">
  1119. <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>
  1120. <input type="range" id="player-size-slider" class="slider" min="50" max="150" value="100">
  1121. </div>
  1122. <div class="enhancement-option">
  1123. <label>Default video player quality: </label>
  1124. <select class="tab-button-active" id="select-video-qualitys-select">
  1125. <option value="144">144</option>
  1126. <option value="240">240</option>
  1127. <option value="360">360</option>
  1128. <option value="480">480</option>
  1129. <option value="720">720</option>
  1130. <option value="1080">1080</option>
  1131. <option value="1440">1440</option>
  1132. <option value="2160">2160</option>
  1133. </select>
  1134. </div>
  1135. </div>
  1136.  
  1137. <div id="themes" class="tab-content" style="height: auto; max-height: 350px; overflow-y: auto;">
  1138. <div class="themes-hidden">
  1139. <h4>Choose a Theme</h4>
  1140. <p>Disable cinematic Lighting</p>
  1141. <label>
  1142. <div class="theme-option">
  1143. <div class="theme-preview" style="background: dark;"></div>
  1144. <input type="radio" name="theme" value="custom">
  1145. <span class="theme-name">Custom</span>
  1146. </div>
  1147. </label>
  1148. <label>
  1149. <div class="theme-option theme-selected-normal">
  1150. <div class="theme-preview" style="background: dark;"></div>
  1151. <input type="radio" name="theme" value="normal">
  1152. <span class="theme-name">Selected Themes</span>
  1153. </div>
  1154. </label>
  1155. <p>${isDarkModeActive ? '' : 'activate dark mode to use themes'}</p>
  1156. <div class="themes-options">
  1157. ${themeOptionsHTML}
  1158. </div>
  1159. <div class="theme-custom-options">
  1160. <div class="enhancement-option">
  1161. <label>Progressbar Video:</label>
  1162. <input type="color" id="progressbar-color-picker" class="color-picker" value="#ff0000">
  1163. </div>
  1164. <div class="enhancement-option">
  1165. <label>Background Color:</label>
  1166. <input type="color" id="bg-color-picker" class="color-picker" value="#000000">
  1167. </div>
  1168. <div class="enhancement-option">
  1169. <label>Primary Color:</label>
  1170. <input type="color" id="primary-color-picker" class="color-picker" value="#ffffff">
  1171. </div>
  1172. <div class="enhancement-option">
  1173. <label>Secondary Color:</label>
  1174. <input type="color" id="secondary-color-picker" class="color-picker" value="#ffffff">
  1175. </div>
  1176. <div class="enhancement-option">
  1177. <label>Header Color:</label>
  1178. <input type="color" id="header-color-picker" class="color-picker" value="#000000">
  1179. </div>
  1180. <div class="enhancement-option">
  1181. <label>Icons Color:</label>
  1182. <input type="color" id="icons-color-picker" class="color-picker" value="#ffffff">
  1183. </div>
  1184. <div class="enhancement-option">
  1185. <label>Menu Color:</label>
  1186. <input type="color" id="menu-color-picker" class="color-picker" value="#000000">
  1187. </div>
  1188. <div class="enhancement-option">
  1189. <label>Line Color Preview:</label>
  1190. <input type="color" id="line-color-picker" class="color-picker" value="#ff0000">
  1191. </div>
  1192. <div class="enhancement-option">
  1193. <label>Time Color Preview:</label>
  1194. <input type="color" id="time-color-picker" class="color-picker" value="#ffffff">
  1195. </div>
  1196. </div>
  1197. </div>
  1198.  
  1199. </div>
  1200.  
  1201. <div id="stats" class="tab-content">
  1202. <div id="yt-stats-toggle">
  1203. <h3 style="margin: 0 0 15px">YouTube Stats</h3>
  1204. <div class="stat-row">
  1205. <div>Foreground Time</div>
  1206. <div class="progress">
  1207. <div class="progress-bar total-bar" id="usage-bar"></div>
  1208. </div>
  1209. <div id="total-time">0h 0m 0s</div>
  1210. </div>
  1211. <div class="stat-row">
  1212. <div>Video Time</div>
  1213. <div class="progress">
  1214. <div class="progress-bar video-bar" id="video-bar"></div>
  1215. </div>
  1216. <div id="video-time">0h 0m 0s</div>
  1217. </div>
  1218. <div class="stat-row">
  1219. <div>Shorts Time</div>
  1220. <div class="progress">
  1221. <div class="progress-bar shorts-bar" id="shorts-bar"></div>
  1222. </div>
  1223. <div id="shorts-time">0h 0m 0s</div>
  1224. </div>
  1225. </div>
  1226. </div>
  1227. <div id="headers" class="tab-content">
  1228. <h4>Available in next update</h4>
  1229. </div>
  1230. <div id="menu-settings" class="tab-content">
  1231. <h4 style="margin: 10px 0">Menu Appearance</h4>
  1232. <div class="enhancement-option">
  1233. <label>Menu Background Color:</label>
  1234. <input type="color" id="menu-bg-color-picker" class="color-picker" value="#000000">
  1235. </div>
  1236. <div class="enhancement-option">
  1237. <label>Menu Text Color:</label>
  1238. <input type="color" id="menu-text-color-picker" class="color-picker" value="#ff0000">
  1239. </div>
  1240. "
  1241. </div>
  1242. <div id="import-export">
  1243. <div style="display: flex;width: 100%;justify-content: space-between;">
  1244. <button id="export-config">Export
  1245. <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>
  1246. </button>
  1247. <button id="import-config">Import
  1248. <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>
  1249. </button>
  1250. </div>
  1251. <textarea id="config-data" placeholder="Paste configuration here to import"></textarea>
  1252. </div>
  1253. `)
  1254. : `
  1255. <div style="display: flex;justify-content: space-between;align-items: center;gap: 3px;margin-bottom: 10px;">
  1256. <h4 style="display: flex;align-items: center;gap: 10px;">YouTube Tools v2.3.3.2 <a target="_blank" href="https://github.com/DeveloperMDCM/Youtube-tools-extension">
  1257. <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>
  1258. </a></h4>
  1259. <div style="display: flex; gap: 5px;">
  1260. <span id="menu-settings-icon">⚙️</span>
  1261. <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>
  1262. <span style="cursor: pointer" class="close_menu_settings">❎</span>
  1263. </div>
  1264. </div>
  1265. <div class="tab-buttons">
  1266. <button class="tab-button active" data-tab="general">General</button>
  1267. <button class="tab-button" data-tab="themes">Themes</button>
  1268. <button class="tab-button" data-tab="stats">Stats</button>
  1269. <button class="tab-button" data-tab="headers">Header</button>
  1270. </div>
  1271. <div id="general" class="tab-content active">
  1272. <div class="enhancement-option">
  1273. <label>
  1274. <input type="checkbox" id="hide-comments-toggle"> Hide Comments
  1275. </label>
  1276. </div>
  1277. <div class="enhancement-option">
  1278. <label>
  1279. <input type="checkbox" id="hide-sidebar-toggle"> Hide Sidebar
  1280. </label>
  1281. </div>
  1282. <div class="enhancement-option">
  1283. <label>
  1284. <input type="checkbox" id="autoplay-toggle"> Disable Autoplay
  1285. </label>
  1286. </div>
  1287. <div class="enhancement-option">
  1288. <label>
  1289. <input type="checkbox" id="subtitles-toggle"> Disable Subtitles
  1290. </label>
  1291. </div>
  1292. <div class="enhancement-option">
  1293. <label>
  1294. <input type="checkbox" id="dislikes-toggle"> Show Dislikes / Reload page
  1295. </label>
  1296. </div>
  1297. <div class="enhancement-option">
  1298. <label>
  1299. <input type="checkbox" id="themes-toggle"> Active Themes / Reload page
  1300. </label>
  1301. </div>
  1302. <div class="enhancement-option">
  1303. <label>
  1304. <input type="checkbox" id="translation-toggle"> Translate comments / Reload page
  1305. </label>
  1306. </div>
  1307. <div class="enhancement-option">
  1308. <label>
  1309. <input type="checkbox" id="avatars-toggle"> Download avatars / Reload page
  1310. </label>
  1311. </div>
  1312. <div class="enhancement-option">
  1313. <label>
  1314. <input type="checkbox" id="reverse-mode-toggle"> Reverse mode
  1315. </label>
  1316. </div>
  1317.  
  1318. <div class="enhancement-option">
  1319. <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>
  1320. <input type="range" id="player-size-slider" class="slider" min="50" max="150" value="100">
  1321. </div>
  1322. <div class="enhancement-option">
  1323. <label>Default video player quality: </label>
  1324. <select class="tab-button-active" id="select-video-qualitys-select">
  1325. <option value="144">144</option>
  1326. <option value="240">240</option>
  1327. <option value="360">360</option>
  1328. <option value="480">480</option>
  1329. <option value="720">720</option>
  1330. <option value="1080">1080</option>
  1331. <option value="1440">1440</option>
  1332. <option value="2160">2160</option>
  1333. </select>
  1334. </div>
  1335. </div>
  1336.  
  1337. <div id="themes" class="tab-content" style="height: auto; max-height: 350px; overflow-y: auto;">
  1338. <div class="themes-hidden">
  1339. <h4>Choose a Theme</h4>
  1340. <p>Disable cinematic Lighting</p>
  1341. <label>
  1342. <div class="theme-option">
  1343. <div class="theme-preview" style="background: dark;"></div>
  1344. <input type="radio" name="theme" value="custom">
  1345. <span class="theme-name">Custom</span>
  1346. </div>
  1347. </label>
  1348. <label>
  1349. <div class="theme-option theme-selected-normal">
  1350. <div class="theme-preview" style="background: dark;"></div>
  1351. <input type="radio" name="theme" value="normal">
  1352. <span class="theme-name">Selected Themes</span>
  1353. </div>
  1354. </label>
  1355. <p>${isDarkModeActive ? '' : 'activate dark mode to use themes'}</p>
  1356. <div class="themes-options">
  1357. ${themeOptionsHTML}
  1358. </div>
  1359. <div class="theme-custom-options">
  1360. <div class="enhancement-option">
  1361. <label>Progressbar Video:</label>
  1362. <input type="color" id="progressbar-color-picker" class="color-picker" value="#ff0000">
  1363. </div>
  1364. <div class="enhancement-option">
  1365. <label>Background Color:</label>
  1366. <input type="color" id="bg-color-picker" class="color-picker" value="#000000">
  1367. </div>
  1368. <div class="enhancement-option">
  1369. <label>Primary Color:</label>
  1370. <input type="color" id="primary-color-picker" class="color-picker" value="#ffffff">
  1371. </div>
  1372. <div class="enhancement-option">
  1373. <label>Secondary Color:</label>
  1374. <input type="color" id="secondary-color-picker" class="color-picker" value="#ffffff">
  1375. </div>
  1376. <div class="enhancement-option">
  1377. <label>Header Color:</label>
  1378. <input type="color" id="header-color-picker" class="color-picker" value="#000000">
  1379. </div>
  1380. <div class="enhancement-option">
  1381. <label>Icons Color:</label>
  1382. <input type="color" id="icons-color-picker" class="color-picker" value="#ffffff">
  1383. </div>
  1384. <div class="enhancement-option">
  1385. <label>Menu Color:</label>
  1386. <input type="color" id="menu-color-picker" class="color-picker" value="#000000">
  1387. </div>
  1388. <div class="enhancement-option">
  1389. <label>Line Color Preview:</label>
  1390. <input type="color" id="line-color-picker" class="color-picker" value="#ff0000">
  1391. </div>
  1392. <div class="enhancement-option">
  1393. <label>Time Color Preview:</label>
  1394. <input type="color" id="time-color-picker" class="color-picker" value="#ffffff">
  1395. </div>
  1396. </div>
  1397. </div>
  1398.  
  1399. </div>
  1400.  
  1401. <div id="stats" class="tab-content">
  1402. <div id="yt-stats-toggle">
  1403. <h3 style="margin: 0 0 15px">YouTube Stats</h3>
  1404. <div class="stat-row">
  1405. <div>Foreground Time</div>
  1406. <div class="progress">
  1407. <div class="progress-bar total-bar" id="usage-bar"></div>
  1408. </div>
  1409. <div id="total-time">0h 0m 0s</div>
  1410. </div>
  1411. <div class="stat-row">
  1412. <div>Video Time</div>
  1413. <div class="progress">
  1414. <div class="progress-bar video-bar" id="video-bar"></div>
  1415. </div>
  1416. <div id="video-time">0h 0m 0s</div>
  1417. </div>
  1418. <div class="stat-row">
  1419. <div>Shorts Time</div>
  1420. <div class="progress">
  1421. <div class="progress-bar shorts-bar" id="shorts-bar"></div>
  1422. </div>
  1423. <div id="shorts-time">0h 0m 0s</div>
  1424. </div>
  1425. </div>
  1426. </div>
  1427. <div id="headers" class="tab-content">
  1428. <h4>Available in next update</h4>
  1429. </div>
  1430. <div id="menu-settings" class="tab-content">
  1431. <h4 style="margin: 10px 0">Menu Appearance</h4>
  1432. <div class="enhancement-option">
  1433. <label>Menu Background Color:</label>
  1434. <input type="color" id="menu-bg-color-picker" class="color-picker" value="#000000">
  1435. </div>
  1436. <div class="enhancement-option">
  1437. <label>Menu Text Color:</label>
  1438. <input type="color" id="menu-text-color-picker" class="color-picker" value="#ff0000">
  1439. </div>
  1440.  
  1441. </div>
  1442. <div id="import-export">
  1443. <div style="display: flex;width: 100%;justify-content: space-between;">
  1444. <button id="export-config" style="width: 100%;display: flex;align-items: center;justify-content: center;">Export
  1445. <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>
  1446. </button>
  1447. <button id="import-config" style="width: 100%;display: flex;align-items: center;justify-content: center;">Import
  1448. <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>
  1449. </button>
  1450. </div>
  1451. <textarea id="config-data" placeholder="Paste configuration here to import"></textarea>
  1452. </div>
  1453. `;
  1454.  
  1455. panel.innerHTML = panelHTML;
  1456. $ap(panel);
  1457.  
  1458.  
  1459. function addIcon() {
  1460. const topBar = $e('ytd-topbar-menu-button-renderer');
  1461. if (!topBar || $id('icon-menu-settings')) return;
  1462.  
  1463. const toggleButton = $cl('div');
  1464. toggleButton.id = 'toggle-button';
  1465.  
  1466. const icon = $cl('img');
  1467. icon.id = 'icon-menu-settings';
  1468. icon.src = 'https://cdn.iconscout.com/icon/premium/png-512-thumb/settings-782-1095915.png?f=webp&w=100';
  1469.  
  1470. toggleButton.appendChild(icon);
  1471. topBar.parentElement.insertBefore(toggleButton, topBar);
  1472. // Toggle panel visibility
  1473. let openMenu = false;
  1474. toggleButton.addEventListener('click', () => {
  1475. openMenu = !openMenu;
  1476. // openMenu
  1477. // ? (toggleButton.style.backgroundColor = '#f00')
  1478. // : (toggleButton.style.backgroundColor = 'transparent');
  1479. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  1480. });
  1481.  
  1482.  
  1483. }
  1484.  
  1485.  
  1486. addIcon();
  1487. let openMenu = false;
  1488.  
  1489. const close_menu_settings = $e('.close_menu_settings');
  1490. close_menu_settings.addEventListener('click', () => {
  1491. openMenu = !openMenu;
  1492. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  1493. });
  1494.  
  1495. // $ap(toggleButton);
  1496.  
  1497.  
  1498.  
  1499.  
  1500. // Tab functionality
  1501. const tabButtons = $m('.tab-button');
  1502. const tabContents = $m('.tab-content');
  1503.  
  1504. tabButtons.forEach((button) => {
  1505. button.addEventListener('click', () => {
  1506. const tabName = button.getAttribute('data-tab');
  1507. tabButtons.forEach((btn) => btn.classList.remove('active'));
  1508. tabContents.forEach((content) => content.classList.remove('active'));
  1509. button.classList.add('active');
  1510. $id(tabName).classList.add('active');
  1511. });
  1512. });
  1513.  
  1514. // Menu settings icon functionality
  1515. $id('menu-settings-icon').addEventListener('click', () => {
  1516. tabButtons.forEach((btn) => btn.classList.remove('active'));
  1517. tabContents.forEach((content) => content.classList.remove('active'));
  1518. $id('menu-settings').classList.add('active');
  1519. });
  1520.  
  1521. // Function to save settings
  1522. function saveSettings() {
  1523. const settings = {
  1524. theme: $e('input[name="theme"]:checked').value,
  1525. bgColorPicker: $id('bg-color-picker').value,
  1526. progressbarColorPicker: $id('progressbar-color-picker').value,
  1527. primaryColorPicker: $id('primary-color-picker').value,
  1528. secondaryColorPicker: $id('secondary-color-picker').value,
  1529. headerColorPicker: $id('header-color-picker').value,
  1530. iconsColorPicker: $id('icons-color-picker').value,
  1531. menuColorPicker: $id('menu-color-picker').value,
  1532. lineColorPicker: $id('line-color-picker').value,
  1533. timeColorPicker: $id('time-color-picker').value,
  1534. dislikes: $id('dislikes-toggle').checked,
  1535. themes: $id('themes-toggle').checked,
  1536. translation: $id('translation-toggle').checked,
  1537. avatars: $id('avatars-toggle').checked,
  1538. reverseMode: $id('reverse-mode-toggle').checked,
  1539. hideComments: $id('hide-comments-toggle').checked,
  1540. hideSidebar: $id('hide-sidebar-toggle').checked,
  1541. disableAutoplay: $id('autoplay-toggle').checked,
  1542. // cinematicLighting: $id('cinematic-lighting-toggle').checked,
  1543. disableSubtitles: $id('subtitles-toggle').checked,
  1544. // fontSize: $id('font-size-slider').value,
  1545. playerSize: $id('player-size-slider').value,
  1546. selectVideoQuality: $id('select-video-qualitys-select').value,
  1547. menuBgColor: $id('menu-bg-color-picker').value,
  1548. menuTextColor: $id('menu-text-color-picker').value,
  1549. // menuFontSize: $id('menu-font-size-slider').value,
  1550. };
  1551.  
  1552. GM_setValue('ytSettingsMDCM', JSON.stringify(settings));
  1553. }
  1554.  
  1555.  
  1556.  
  1557. // Function to load settings
  1558. function loadSettings() {
  1559. const settings = JSON.parse(GM_getValue('ytSettingsMDCM', '{}'));
  1560. if (settings.theme) {
  1561. $e(`input[name="theme"][value="${settings.theme}"]`).checked = true;
  1562. }
  1563.  
  1564. $id('bg-color-picker').value = settings.bgColorPicker || '#000000';
  1565. $id('progressbar-color-picker').value = settings.progressbarColorPicker || '#ff0000';
  1566. $id('primary-color-picker').value = settings.primaryColorPicker || '#ffffff';
  1567. $id('secondary-color-picker').value = settings.secondaryColorPicker || '#ffffff';
  1568. $id('header-color-picker').value = settings.headerColorPicker || '#000';
  1569. $id('icons-color-picker').value = settings.iconsColorPicker || '#ffffff';
  1570. $id('menu-color-picker').value = settings.menuColorPicker || '#000';
  1571. $id('line-color-picker').value = settings.lineColorPicker || '#ff0000';
  1572. $id('time-color-picker').value = settings.timeColorPicker || '#ffffff';
  1573. $id('dislikes-toggle').checked = settings.dislikes || true;
  1574. $id('themes-toggle').checked = settings.themes || false;
  1575. $id('translation-toggle').checked = settings.translation || false;
  1576. $id('avatars-toggle').checked = settings.avatars || false;
  1577. $id('reverse-mode-toggle').checked = settings.reverseMode || false;
  1578. $id('hide-comments-toggle').checked = settings.hideComments || false;
  1579. $id('hide-sidebar-toggle').checked = settings.hideSidebar || false;
  1580. $id('autoplay-toggle').checked = settings.disableAutoplay || false;
  1581. // $id('cinematic-lighting-toggle').checked = settings.cinematicLighting || false;
  1582. $id('subtitles-toggle').checked = settings.disableSubtitles || false;
  1583. // $id('font-size-slider').value = settings.fontSize || 16;
  1584. $id('player-size-slider').value = settings.playerSize || 100;
  1585. $id('select-video-qualitys-select').value = settings.selectVideoQuality || '720';
  1586. $id('menu-bg-color-picker').value = settings.menuBgColor || '#000000';
  1587. $id('menu-text-color-picker').value = settings.menuTextColor || '#ffffff';
  1588. // $id('menu-font-size-slider').value = settings.menuFontSize || 14;
  1589. updateSliderValues();
  1590.  
  1591. setTimeout(() => {
  1592. applySettings();
  1593. if(settings.dislikes) {
  1594. videoDislike();
  1595. shortDislike();
  1596. showDislikes = true;
  1597. }
  1598. }, 500);
  1599. }
  1600. // Function to update slider values
  1601. function updateSliderValues() {
  1602. // $id('font-size-value').textContent = $id('font-size-slider').value;
  1603. $id('player-size-value').textContent = $id('player-size-slider').value;
  1604. // $id('menu-font-size-value').textContent = $id('menu-font-size-slider').value;
  1605. }
  1606.  
  1607. $id('reset-player-size').addEventListener('click', () => {
  1608. $id('player-size-slider').value = 100;
  1609. updateSliderValues();
  1610. applySettings();
  1611. });
  1612.  
  1613. // Function to apply settings
  1614. function applySettings() {
  1615. const formulariodescarga = $e('.formulariodescarga');
  1616. const formulariodescargaaudio = $e('.formulariodescargaaudio');
  1617. if (formulariodescarga != undefined) {
  1618. formulariodescarga.classList.add('ocultarframe');
  1619. formulariodescargaaudio.classList.add('ocultarframe');
  1620. }
  1621. const settings = {
  1622. theme: $e('input[name="theme"]:checked').value,
  1623. bgColorPicker: $id('bg-color-picker').value,
  1624. progressbarColorPicker: $id('progressbar-color-picker').value,
  1625. primaryColorPicker: $id('primary-color-picker').value,
  1626. secondaryColorPicker: $id('secondary-color-picker').value,
  1627. headerColorPicker: $id('header-color-picker').value,
  1628. iconsColorPicker: $id('icons-color-picker').value,
  1629. menuColorPicker: $id('menu-color-picker').value,
  1630. lineColorPicker: $id('line-color-picker').value,
  1631. timeColorPicker: $id('time-color-picker').value,
  1632. dislikes: $id('dislikes-toggle').checked,
  1633. themes: $id('themes-toggle').checked,
  1634. translation: $id('translation-toggle').checked,
  1635. avatars: $id('avatars-toggle').checked,
  1636. reverseMode: $id('reverse-mode-toggle').checked,
  1637. hideComments: $id('hide-comments-toggle').checked,
  1638. hideSidebar: $id('hide-sidebar-toggle').checked,
  1639. disableAutoplay: $id('autoplay-toggle').checked,
  1640. // cinematicLighting: $id('cinematic-lighting-toggle').checked,
  1641. disableSubtitles: $id('subtitles-toggle').checked,
  1642. // fontSize: $id('font-size-slider').value,
  1643. playerSize: $id('player-size-slider').value,
  1644. selectVideoQuality: $id('select-video-qualitys-select').value,
  1645. menuBgColor: $id('menu-bg-color-picker').value,
  1646. menuTextColor: $id('menu-text-color-picker').value,
  1647. // menuFontSize: $id('menu-font-size-slider').value,
  1648. };
  1649.  
  1650.  
  1651. renderizarButtons();
  1652. function isFullscreen() {
  1653. return document.fullscreenElement !== null;
  1654. }
  1655.  
  1656.  
  1657. document.addEventListener("fullscreenchange", () => {
  1658. let panel = $e('#toggle-panel');
  1659. if (isFullscreen()) {
  1660. panel.style.opacity = 0;
  1661. } else {
  1662. panel.style.opacity = 1;
  1663. }
  1664. });
  1665.  
  1666.  
  1667. // Hide comments
  1668. const commentsSection = $id('comments');
  1669. if (commentsSection) {
  1670. commentsSection.style.display = settings.hideComments ? 'none' : 'block';
  1671. }
  1672.  
  1673. // Active inactive Themes
  1674. const themesMenuSection = $e('.themes-hidden');
  1675. if (themesMenuSection) {
  1676. themesMenuSection.style.display = settings.themes ? 'block' : 'none';
  1677. }
  1678.  
  1679. // Hide sidebar
  1680. const sidebarSection = $e('#secondary > #secondary-inner');
  1681.  
  1682. if (sidebarSection) {
  1683. sidebarSection.classList.add('side-moi');
  1684. const sidebarSection2 = $e('.side-moi');
  1685.  
  1686. sidebarSection2.style.display = settings.hideSidebar ? 'none' : 'block';
  1687. }
  1688.  
  1689. // Disable autoplay
  1690. const autoplayToggle = $e('.ytp-autonav-toggle-button');
  1691. if (autoplayToggle) {
  1692. const isCurrentlyOn =
  1693. autoplayToggle.getAttribute('aria-checked') === 'true';
  1694. if (settings.disableAutoplay && isCurrentlyOn) {
  1695. autoplayToggle.click();
  1696. } else if (!settings.disableAutoplay && !isCurrentlyOn) {
  1697. autoplayToggle.click();
  1698. }
  1699. }
  1700. // Disable subtitles
  1701. const subtitleToggle = $e('.ytp-subtitles-button');
  1702. if (subtitleToggle) {
  1703. const isCurrentlyOn =
  1704. subtitleToggle.getAttribute('aria-pressed') === 'true';
  1705. if (settings.disableSubtitles && isCurrentlyOn) {
  1706. subtitleToggle.click();
  1707. } else if (!settings.disableSubtitles && !isCurrentlyOn) {
  1708. subtitleToggle.click();
  1709. }
  1710. }
  1711. // Disable cinematicLighting
  1712. // const buttonSettingVideo = $e(".ytp-settings-button");
  1713. // if(buttonSettingVideo && !settings.cinematicLighting) {
  1714. // buttonSettingVideo.click();
  1715. // setTimeout(() => {
  1716. // buttonSettingVideo.click();
  1717. // },50)
  1718. // }
  1719.  
  1720.  
  1721. // Adjust font size
  1722. // $e('body').style.fontSize = `${settings.fontSize}px`;
  1723.  
  1724. // Adjust player size
  1725. const player = $e('video');
  1726. if (player) {
  1727. player.style.transform = `scale(${settings.playerSize / 100})`;
  1728. }
  1729.  
  1730. // selected video quality
  1731. const video = $e('div#movie_player');
  1732. let ytPlayerQuality = localStorage.getItem('yt-player-quality');
  1733. $e('#select-video-qualitys-select').addEventListener('change', () => {
  1734. applySettings();
  1735. })
  1736.  
  1737. if (video != undefined) {
  1738. if (ytPlayerQuality) {
  1739. let qualitySettings = JSON.parse(ytPlayerQuality);
  1740. qualitySettings.data = JSON.stringify({ quality: settings.selectVideoQuality, previousQuality: 240 });
  1741. localStorage.setItem('yt-player-quality', JSON.stringify(qualitySettings));
  1742.  
  1743. } else {
  1744. let defaultQualitySettings = {
  1745. data: JSON.stringify({ quality: 720, previousQuality: 240 }),
  1746. expiration: Date.now() + (365 * 24 * 60 * 60 * 1000),
  1747. creation: Date.now()
  1748. };
  1749. localStorage.setItem('yt-player-quality', JSON.stringify(defaultQualitySettings));
  1750. }
  1751. }
  1752.  
  1753.  
  1754. // Apply menu appearance settings
  1755. $sp('--yt-enhance-menu-bg', settings.menuBgColor);
  1756. $sp('--yt-enhance-menu-text', settings.menuTextColor);
  1757. // $sp('--yt-enhance-menu-font-size', `${settings.menuFontSize}px`);
  1758.  
  1759. // Apply theme
  1760. const selectedTheme = themes[settings.theme];
  1761.  
  1762. const isThemeCustom = $e(`input[name="theme"][value="custom"]`).checked;
  1763. const isThemeNormal = $e(`input[name="theme"][value="normal"]`).checked;
  1764. const themeCustomOptions = $e('.theme-custom-options');
  1765. const themeNormal = $e('.theme-selected-normal');
  1766. if(isThemeCustom != undefined) {
  1767. themeNormal.style.display = "block"
  1768. themeCustomOptions.style.display = "block";
  1769. $e('.themes-options').style.display = "none";
  1770. }
  1771. if(isThemeNormal) {
  1772. $e(`input[name="theme"][value="custom"]`).checked = false;
  1773. }
  1774.  
  1775.  
  1776.  
  1777.  
  1778. function checkDarkMode() {
  1779. if(settings.themes) {
  1780. if (isDarkMode && !isThemeCustom) {
  1781. // Apply theme
  1782. $e('.themes-options').style.display = "block";
  1783. themeNormal.style.display = "none";
  1784. themeCustomOptions.style.display = "none";
  1785. if(settings.theme === 'normal') {
  1786. $e(`input[name="theme"][value="0"]`).checked = true;
  1787. // applySettings();
  1788. } else {
  1789.  
  1790. $sp('--yt-spec-base-background', selectedTheme.gradient);
  1791. $sp('--yt-spec-text-primary', selectedTheme.textColor);
  1792. $sp('--yt-spec-text-secondary', selectedTheme.textColor);
  1793. $sp('--yt-spec-menu-background', selectedTheme.gradient);
  1794. $sp('--yt-spec-icon-inactive', selectedTheme.textColor);
  1795. $sp('--yt-spec-brand-icon-inactive', selectedTheme.textColor);
  1796. $sp('--yt-spec-brand-icon-active', selectedTheme.gradient);
  1797. $sp('--yt-spec-static-brand-red', selectedTheme.gradient); // line current time
  1798. $sp('--yt-spec-raised-background', selectedTheme.raised);
  1799. $sp('--yt-spec-static-brand-red', selectedTheme.CurrentProgressVideo);
  1800. $sp('--yt-spec-static-brand-white', selectedTheme.textColor);
  1801. $sp('--ytd-searchbox-background', selectedTheme.gradient);
  1802. $sp('--ytd-searchbox-text-color', selectedTheme.textColor);
  1803. $sp('--ytcp-text-primary', settings.textColor);
  1804. GM_addStyle(`
  1805.  
  1806. .botones_div {
  1807. background-color: transparent;
  1808. border: none;
  1809. color: #999999;
  1810. user-select: none;
  1811. }
  1812. .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox {
  1813. background: ${selectedTheme.gradient} !important;
  1814. }
  1815. #background.ytd-masthead { background: ${selectedTheme.gradient} !important; }
  1816. .ytp-swatch-background-color {
  1817. background: ${
  1818. selectedTheme.gradient
  1819. } !important;
  1820. }
  1821. #shorts-container, #page-manager.ytd-app {
  1822. background: ${selectedTheme.gradient.replace(/(#[0-9a-fA-F]{6})/g, `$1${36}`)};
  1823. }
  1824. ytd-engagement-panel-title-header-renderer[shorts-panel] #header.ytd-engagement-panel-title-header-renderer {
  1825. background: ${selectedTheme.gradient} !important;}
  1826. .buttons-tranlate {
  1827. background: ${selectedTheme.btnTranslate} !important;
  1828. }
  1829. .badge-shape-wiz--thumbnail-default {
  1830. color: ${selectedTheme.videoDuration} !important;
  1831. background: ${selectedTheme.gradient} !important;
  1832. }
  1833. #logo-icon {
  1834. color: ${selectedTheme.textLogo} !important;
  1835. }
  1836. .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--text {
  1837. color: ${selectedTheme.iconsColor} !important;
  1838. }
  1839. .ytd-topbar-menu-button-renderer #button.ytd-topbar-menu-button-renderer {
  1840. color: ${selectedTheme.iconsColor} !important;
  1841. }
  1842. .yt-spec-icon-badge-shape--style-overlay .yt-spec-icon-badge-shape__icon {
  1843. color: ${selectedTheme.iconsColor} !important;
  1844. }
  1845. .ytp-svg-fill {
  1846. fill: ${selectedTheme.iconsColor} !important;
  1847. }
  1848. #ytp-id-30,#ytp-id-17,#ytp-id-19,#ytp-id-20{
  1849. fill: ${selectedTheme.iconsColor} !important;
  1850. }
  1851.  
  1852.  
  1853. `);
  1854. }
  1855.  
  1856. } else {
  1857. $sp('--yt-spec-base-background', settings.bgColorPicker);
  1858. $sp('--yt-spec-text-primary', settings.primaryColorPicker);
  1859. $sp('--yt-spec-text-secondary', settings.secondaryColorPicker);
  1860. $sp('--yt-spec-menu-background', settings.menuColorPicker);
  1861. $sp('--yt-spec-icon-inactive', settings.iconsColorPicker);
  1862. $sp('--yt-spec-brand-icon-inactive', settings.primaryColorPicker);
  1863. $sp('--yt-spec-brand-icon-active', settings.primaryColorPicker);
  1864. $sp('--yt-spec-raised-background', settings.headerColorPicker);
  1865. $sp('--yt-spec-static-brand-red', settings.lineColorPicker);
  1866. $sp('--yt-spec-static-brand-white', settings.timeColorPicker);
  1867. $sp('--ytd-searchbox-background', settings.primaryColorPicker);
  1868. $sp('--ytd-searchbox-text-color', settings.secondaryColorPicker);
  1869. $sp('--ytcp-text-primary', settings.primaryColorPicker);
  1870. GM_addStyle(`
  1871. .html5-video-player {
  1872. color: ${settings.primaryColorPicker} !important;
  1873. }
  1874. .ytp-volume-slider-handle:before, .ytp-volume-slider-handle, .ytp-tooltip.ytp-preview:not(.ytp-text-detail) {
  1875. background-color: ${settings.iconsColorPicker} !important;
  1876. }
  1877. .ytp-autonav-toggle-button[aria-checked=true] {
  1878. background-color: ${settings.iconsColorPicker} !important;
  1879. }
  1880. .tp-yt-iron-icon {
  1881. fill: ${settings.iconsColorPicker} !important;
  1882. }
  1883.  
  1884. #columns.style-scope.ytd-watch-flexy {
  1885. flex-direction: ${settings.reverseMode ? 'row-reverse' : 'row'} !important;
  1886. padding-left: ${settings.reverseMode ? '20px' : '0'} !important;
  1887. }
  1888. #secondary.style-scope.ytd-watch-flexy {
  1889. display: ${settings.hideSidebar ? 'none' : 'block'} !important;
  1890. }
  1891. .html5-video-container video {
  1892. width: ${settings.hideSidebar ? '100%' : ''} !important;
  1893. height: ${settings.hideSidebar ? 'fit-content' : ''} !important;
  1894. }
  1895. .ytp-chrome-bottom {
  1896. width: ${settings.hideSidebar ? '100%' : ''} !important;
  1897. left: ${settings.hideSidebar ? 'auto' : ''} !important;
  1898. }
  1899. .ytp-progress-bar-container {
  1900. left: ${settings.hideSidebar ? '4px' : ''} !important;
  1901. }
  1902. .botones_div {
  1903. background-color: transparent;
  1904. border: none;
  1905. color: ${settings.iconsColorPicker} !important;
  1906. user-select: none;
  1907. }
  1908. .ytp-volume-slider-handle:before, .ytp-volume-slider-handle, .ytp-tooltip.ytp-preview:not(.ytp-text-detail){
  1909. background-color:
  1910. }
  1911. #container.ytd-searchbox {
  1912. color: red !important;
  1913. }
  1914. .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox {
  1915. background: ${settings.primaryColorPicker} !important;
  1916. }
  1917. .yt-spec-icon-shape {
  1918. display: flex;
  1919. align-items: center;
  1920. justify-content: center;
  1921. width: 100%;
  1922. height: 100%;
  1923. color: ${settings.iconsColorPicker} !important;
  1924. }
  1925. .ytp-time-current, .ytp-time-separator, .ytp-time-duration {
  1926. color: ${settings.iconsColorPicker} !important;
  1927. }
  1928. #background.ytd-masthead { background: ${settings.headerColorPicker} !important; }
  1929. .ytp-swatch-background-color {
  1930. background: ${
  1931. settings.progressbarColorPicker
  1932. } !important;
  1933. }
  1934. #shorts-container, #page-manager.ytd-app {
  1935. background: ${settings.bgColorPicker}36;
  1936. }
  1937. ytd-engagement-panel-title-header-renderer[shorts-panel] #header.ytd-engagement-panel-title-header-renderer {
  1938. background: ${settings.bgColorPicker} !important;}
  1939.  
  1940. .badge-shape-wiz--thumbnail-default {
  1941. color: ${settings.timeColorPicker} !important;
  1942. background: ${settings.secondaryColor} !important;
  1943. }
  1944. #logo-icon {
  1945. color: ${settings.primaryColorPicker} !important;
  1946. }
  1947. .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--text {
  1948. color: ${settings.iconsColorPicker} !important;
  1949. }
  1950. .ytd-topbar-menu-button-renderer #button.ytd-topbar-menu-button-renderer {
  1951. color: ${settings.iconsColorPicker} !important;
  1952. }
  1953. .yt-spec-icon-badge-shape--style-overlay .yt-spec-icon-badge-shape__icon {
  1954. color: ${settings.iconsColorPicker} !important;
  1955. }
  1956. .ytp-svg-fill {
  1957. fill: ${settings.iconsColorPicker} !important;
  1958. }
  1959. #ytp-id-30,#ytp-id-17,#ytp-id-19,#ytp-id-20{
  1960. fill: ${settings.iconsColorPicker} !important;
  1961. }
  1962. `);
  1963. }
  1964. } else {
  1965. GM_addStyle(`
  1966. .botones_div {
  1967. background-color: transparent;
  1968. border: none;
  1969. color: #ccc !important;
  1970. user-select: none;
  1971. }
  1972. `)
  1973. }
  1974. }
  1975.  
  1976.  
  1977.  
  1978. checkDarkMode();
  1979. let currentUrl = window.location.href;
  1980. let urlCheckInterval = setInterval(function () {
  1981. if (window.location.href !== currentUrl) {
  1982. currentUrl = window.location.href;
  1983. checkUrlChange();
  1984. }
  1985. }, 1000);
  1986.  
  1987. function checkUrlChange() {
  1988. setTimeout(() => {
  1989. applySettings();
  1990. }, 1000);
  1991. clearInterval(urlCheckInterval);
  1992. }
  1993.  
  1994. let traducido; // Texto traducido
  1995. let urlLista; // Url lista
  1996. async function traductor() {
  1997. const texto = $m('#content-text');
  1998. if ($e('.buttons-tranlate')) return;
  1999. let o = `?client=dict-chrome-ex&sl=auto&tl=${navigator.language}&q=`;
  2000. for (let i = 0; i < texto.length; i++) {
  2001. const botonTraducir = $cl('BUTTON');
  2002. botonTraducir.classList.add('buttons-tranlate');
  2003. botonTraducir.textContent = 'Translate';
  2004. botonTraducir.setAttribute('id', `btn${i}`);
  2005. texto[i].insertAdjacentElement('afterend', botonTraducir);
  2006. const mdcm = $m(`.buttons-tranlate`);
  2007. mdcm[i].onclick = function () {
  2008. traducido = o;
  2009. urlLista = traducido + texto[i].textContent;
  2010. fetch('https://translate.googleapis.com/translate_a/t' + urlLista) //API
  2011. .then((response) => response.json())
  2012. .then((datos) => {
  2013. texto[i].textContent = datos[0][0];
  2014. mdcm[i].textContent = 'Translated';
  2015. });
  2016. };
  2017. }
  2018. }
  2019.  
  2020. function limpiarHTML(selector) {
  2021. $m(selector).forEach((button) => button.remove());
  2022. }
  2023.  
  2024. function checkScroll () {
  2025. const avatars = $m('#author-thumbnail-button #img.style-scope.yt-img-shadow');
  2026.  
  2027. if (avatars.length > 0 && settings.avatars) {
  2028. limpiarHTML('.yt-image-avatar-download');
  2029. agregarBotonesDescarga();
  2030. }
  2031.  
  2032. const divEl = $e('#content-text');
  2033. const divEl2 = $e('ytd-item-section-renderer[static-comments-header] #contents');
  2034.  
  2035. if (settings.translation) {
  2036. if (divEl !== undefined || divEl2 !== undefined) {
  2037. limpiarHTML('.buttons-tranlate');
  2038. traductor();
  2039. }
  2040. }
  2041.  
  2042. }
  2043.  
  2044. window.onscroll = () => {
  2045. checkScroll();
  2046. }
  2047.  
  2048.  
  2049. const contentScrollable = $e('.anchored-panel.style-scope.ytd-shorts #contents.style-scope.ytd-item-section-renderer.style-scope.ytd-item-section-renderer');
  2050. if (contentScrollable) {
  2051. const observer = new IntersectionObserver((entries) => {
  2052. entries.forEach(entry => {
  2053. if (entry.isIntersecting) {
  2054. contentScrollable.addEventListener('scroll', () => {
  2055. checkScroll();
  2056. });
  2057. }
  2058. });
  2059. }, { threshold: 0.1 });
  2060.  
  2061. observer.observe(contentScrollable);
  2062. }
  2063.  
  2064. function agregarBotonesDescarga() {
  2065. const avatars = $m('#author-thumbnail-button #img.style-scope.yt-img-shadow');
  2066.  
  2067.  
  2068. avatars.forEach((img) => {
  2069.  
  2070. if (img.parentElement.querySelector('.yt-image-avatar-download')) return;
  2071.  
  2072. const button = $cl('button');
  2073. button.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-photo-down"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 8h.01" /><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 d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l4 4" /><path d="M14 14l1 -1c.653 -.629 1.413 -.815 2.13 -.559" /><path d="M19 16v6" /><path d="M22 19l-3 3l-3 -3" /></svg>';
  2074. button.classList.add('yt-image-avatar-download');
  2075.  
  2076. // Asigna la funcionalidad de descarga
  2077. button.onclick = async function () {
  2078. try {
  2079. const imageUrl = img.src.split('=')[0];
  2080. const response = await fetch(imageUrl);
  2081. const blob = await response.blob();
  2082. const blobUrl = URL.createObjectURL(blob);
  2083.  
  2084. const parentComment = img.closest('ytd-comment-thread-renderer, ytd-comment-renderer');
  2085. const nameElement = parentComment?.querySelector('#author-text');
  2086. let authorName = nameElement ? nameElement.textContent.trim() : 'avatar';
  2087. authorName = authorName.replace(/[\/\\:*?"<>|]/g, '');
  2088.  
  2089. const link = $cl('a');
  2090. link.href = blobUrl;
  2091. link.download = `${authorName}_avatar.jpg` || 'avatar.jpg';
  2092. document.body.appendChild(link);
  2093. link.click();
  2094. document.body.removeChild(link);
  2095. URL.revokeObjectURL(blobUrl);
  2096. } catch (error) {
  2097. console.error('Error al descargar la imagen:', error);
  2098. }
  2099. };
  2100.  
  2101. // Agrega el botón al contenedor de la imagen
  2102. img.parentElement.style.position = 'relative'; // Asegura que el botón se posicione correctamente
  2103. img.parentElement.appendChild(button);
  2104. });
  2105. }
  2106.  
  2107. const BUTTON_CLASS = 'custom-classic-btn';
  2108.  
  2109.  
  2110. const redirectToClassic = () => {
  2111. const videoId = window.location.pathname.split('/').pop();
  2112. const classicUrl = `https://www.youtube.com/watch?v=${videoId}`;
  2113.  
  2114. window.open(classicUrl, '_blank');
  2115.  
  2116. $e('video.video-stream.html5-main-video').pause();
  2117.  
  2118. };
  2119.  
  2120.  
  2121.  
  2122. const createButton = () => {
  2123. const button = $cl('button');
  2124. button.classList.add(BUTTON_CLASS);
  2125. button.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-screen-share"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M21 12v3a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10a1 1 0 0 1 1 -1h9" /><path d="M7 20l10 0" /><path d="M9 16l0 4" /><path d="M15 16l0 4" /><path d="M17 4h4v4" /><path d="M16 9l5 -5" /></svg>';
  2126. button.title = 'Classic mode';
  2127. button.onclick = redirectToClassic;
  2128. return button;
  2129. };
  2130.  
  2131. const insertButtons = () => {
  2132. const isShortsPage = document.location.pathname.startsWith('/shorts');
  2133.  
  2134. if (isShortsPage) {
  2135. $m('#actions').forEach(actionsContainer => {
  2136. if (!actionsContainer.querySelector(`.${BUTTON_CLASS}`)) {
  2137. actionsContainer.prepend(createButton());
  2138. }
  2139. });
  2140. } else {
  2141. $m(`.${BUTTON_CLASS}`).forEach(button => button.remove());
  2142. }
  2143. };
  2144.  
  2145. const observeDOM = () => {
  2146. const observer = new MutationObserver(() => {
  2147. insertButtons();
  2148. addIcon();
  2149. // obs.disconnect();
  2150. });
  2151. observer.observe(document.body, {
  2152. childList: true,
  2153. subtree: true
  2154. });
  2155. };
  2156.  
  2157. insertButtons();
  2158. observeDOM();
  2159.  
  2160.  
  2161. const targetNode = $e('body');
  2162.  
  2163. if (targetNode != undefined) {
  2164. const element = $e('ytd-item-section-renderer[static-comments-header] #contents');
  2165. if(element != undefined && settings.theme !== 'custom') {
  2166. const observerElementDom = (elem) => {
  2167. const observer = new IntersectionObserver(entries => {
  2168.  
  2169. if(entries[0].isIntersecting) {
  2170.  
  2171. element.style.background = `${selectedTheme.gradient ?? ''}`;
  2172. } else {return}
  2173. })
  2174.  
  2175. return observer.observe($e(`${elem}`))
  2176.  
  2177. }
  2178. observerElementDom('ytd-item-section-renderer[static-comments-header] #contents')
  2179. }
  2180. }
  2181. saveSettings();
  2182. }
  2183.  
  2184. let validoBotones = true;
  2185. function renderizarButtons() {
  2186. const addButton = $e('.style-scope .ytd-watch-metadata');
  2187. const addButton2 = $e('#contents');
  2188.  
  2189. if (addButton != undefined && validoBotones) {
  2190. validoBotones = false;
  2191. const isVisible = !!(
  2192. addButton.offsetWidth ||
  2193. addButton.offsetHeight ||
  2194. addButton.getClientRects().length
  2195. );
  2196. if (isVisible) {
  2197. addButton.insertAdjacentHTML("beforebegin", menuBotones);
  2198. } else if (addButton2 != undefined) {
  2199. addButton.insertAdjacentHTML("beforebegin", menuBotones);
  2200. }
  2201. }
  2202.  
  2203. const formulariodescarga = $e('.formulariodescarga');
  2204. const formulariodescargaaudio = $e('.formulariodescargaaudio');
  2205. const framedescarga = $e('#descargando');
  2206. const framedescargamp3 = $e('#descargandomp3');
  2207. const btn1mp4 = $e('.btn1');
  2208. const btn2mp3 = $e('.btn2');
  2209. const btn3cancel = $e('.btn3');
  2210. const selectcalidades = $e('.selectcalidades');
  2211. const selectcalidadesaudio = $e('.selectcalidadesaudio');
  2212.  
  2213.  
  2214. [formulariodescarga, formulariodescargaaudio].forEach(form =>
  2215. form?.addEventListener('click', e => e.preventDefault())
  2216. );
  2217.  
  2218. selectcalidades?.addEventListener('change', e => {
  2219. framedescarga.src = `https://loader.to/api/button/?url=${window.location.href}&f=${e.target.value}&color=0af`;
  2220. framedescarga.classList.remove('ocultarframe');
  2221. });
  2222.  
  2223. selectcalidadesaudio?.addEventListener('change', e => {
  2224. framedescargamp3.src = `https://loader.to/api/button/?url=${window.location.href}&f=${e.target.value}&color=049c16`;
  2225. framedescargamp3.classList.remove('ocultarframeaudio');
  2226. });
  2227.  
  2228. btn3cancel?.addEventListener('click', () => {
  2229. formulariodescarga.style.display = 'none';
  2230. formulariodescargaaudio.style.display = 'none';
  2231. });
  2232.  
  2233. btn1mp4?.addEventListener('click', () => {
  2234. selectcalidades?.classList.remove('ocultarframe');
  2235. framedescarga?.classList.add('ocultarframe');
  2236. formulariodescarga?.classList.remove('ocultarframe');
  2237. formulariodescarga.style.display = '';
  2238. selectcalidadesaudio?.classList.add('ocultarframeaudio');
  2239. formulariodescargaaudio?.classList.add('ocultarframe');
  2240. formulariodescarga?.reset();
  2241. });
  2242.  
  2243. btn2mp3?.addEventListener('click', () => {
  2244. formulariodescargaaudio?.classList.remove('ocultarframe');
  2245. formulariodescarga?.classList.add('ocultarframe');
  2246. framedescargamp3?.classList.remove('ocultarframeaudio');
  2247. formulariodescargaaudio.style.display = '';
  2248. selectcalidadesaudio?.classList.remove('ocultarframeaudio');
  2249. framedescargamp3?.classList.add('ocultarframeaudio');
  2250. formulariodescargaaudio?.reset();
  2251. });
  2252. // Invertir contenido
  2253.  
  2254. // const background_image = $e('#background_image');
  2255. // const color_bg = $e('#color_bg');
  2256. // const alertShown = localStorage.getItem('alertShown');
  2257. // const alertShownBg = localStorage.getItem('alertShownBg');
  2258. // if (!alertShown) {
  2259. // color_bg.addEventListener('change', () => {
  2260. // alert('disable cinematic mode in the video');
  2261. // localStorage.setItem('alertShown', true);
  2262. // });
  2263. // }
  2264. // if (!alertShownBg) {
  2265. // background_image.addEventListener('input', () => {
  2266. // alert('disable cinematic mode in the video');
  2267. // localStorage.setItem('alertShownBg', true);
  2268. // });
  2269. // }
  2270.  
  2271.  
  2272.  
  2273. const btnImagen = $e('#imagen');
  2274. const formularioButtons = $e('#eyes');
  2275.  
  2276. function initClickEvent() {
  2277. const bufferVideo = $e('.buffer_video');
  2278.  
  2279. if (!bufferVideo) {
  2280.  
  2281. return;
  2282. }
  2283.  
  2284. // Evita duplicar el evento
  2285. if (!bufferVideo.dataset.listenerAdded) {
  2286. bufferVideo.addEventListener("click", () => {
  2287. const video = $e("video.video-stream.html5-main-video");
  2288.  
  2289. if (!video) {
  2290. console.log("No se encontró el video en la página.");
  2291. return;
  2292. }
  2293.  
  2294. // Simular clic derecho
  2295. const event = new MouseEvent("contextmenu", {
  2296. bubbles: true,
  2297. cancelable: true
  2298. });
  2299.  
  2300. video.dispatchEvent(event);
  2301.  
  2302. setTimeout(() => {
  2303. const option = $e("body > div.ytp-popup.ytp-contextmenu > div > div > div:nth-child(7)");
  2304. if (option) {
  2305. option.click();
  2306. } else {
  2307. console.log("Opción no encontrada, intenta aumentar el tiempo de espera.");
  2308. }
  2309. }, 1000);
  2310. });
  2311.  
  2312. bufferVideo.dataset.listenerAdded = "true";
  2313. console.log("Evento registrado con éxito.");
  2314. }
  2315. }
  2316.  
  2317. setInterval(initClickEvent, 2000);
  2318.  
  2319.  
  2320.  
  2321. // valido modo oscuro y venta de video
  2322. // Repeat video button
  2323. let countRepeat = 0; // count
  2324. const repeat = $e('#repeatvideo'); // Repeat button
  2325. const imarepeat = $e('.icon-tabler-repeat'); // img repeat
  2326. const videoFull = $e(
  2327. '#movie_player > div.html5-video-container > video'
  2328. );
  2329. if(repeat != undefined) {
  2330.  
  2331. repeat.onclick = () => {
  2332. if (
  2333. $e('#cinematics > div') != undefined ||
  2334. videoFull != undefined
  2335. ) {
  2336. countRepeat += 1;
  2337. setInterval(() => {
  2338. switch (countRepeat) {
  2339. case 1:
  2340. document
  2341. .querySelector(
  2342. '#movie_player > div.html5-video-container > video'
  2343. )
  2344. .setAttribute('loop', 'true');
  2345. 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">
  2346. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  2347. <path d="M4 12v-3c0 -1.336 .873 -2.468 2.08 -2.856m3.92 -.144h10m-3 -3l3 3l-3 3"></path>
  2348. <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>
  2349. <path d="M3 3l18 18"></path>
  2350. </svg> `; // img repeat
  2351. break;
  2352. case 2:
  2353. countRepeat = 0;
  2354. document
  2355. .querySelector(
  2356. '#movie_player > div.html5-video-container > video'
  2357. )
  2358. .removeAttribute('loop');
  2359. imarepeat.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-repeat" width="24"
  2360. height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
  2361. stroke-linecap="round" stroke-linejoin="round">
  2362. <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  2363. <path d="M4 12v-3a3 3 0 0 1 3 -3h13m-3 -3l3 3l-3 3"></path>
  2364. <path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path>
  2365. </svg>`;
  2366. break;
  2367. }
  2368. }, 1000);
  2369. }
  2370. }
  2371. }
  2372.  
  2373. // Background transparent
  2374.  
  2375. const cinematica = $e('#cinematics > div');
  2376. if (cinematica != undefined) {
  2377. cinematica.style =
  2378. 'position: fixed; inset: 0px; pointer-events: none; transform: scale(1.5, 2)';
  2379. }
  2380. const btnReset = $e('#reset_button'); // Reset button
  2381. if (btnReset != undefined) {
  2382. btnReset.addEventListener('click', function () {
  2383. if (localStorage.getItem('colores') != null) {
  2384. localStorage.removeItem('colores');
  2385. $e('#ojosprotect').style.backgroundColor =
  2386. 'transparent';
  2387. setTimeout(() => {
  2388. location.reload();
  2389. }, 400);
  2390. }
  2391. });
  2392. }
  2393.  
  2394. if (btnImagen != undefined) {
  2395. btnImagen.onclick = () => {
  2396. if (
  2397. $e('#cinematics > div') != undefined ||
  2398. videoFull != undefined
  2399. ) {
  2400. const parametrosURL = new URLSearchParams(window.location.search);
  2401. let enlace = parametrosURL.get('v');
  2402.  
  2403. // Construir la URL de la imagen
  2404. const imageUrl = `https://i.ytimg.com/vi/${enlace}/maxresdefault.jpg`;
  2405.  
  2406. // Realizar la solicitud para obtener la imagen
  2407. fetch(imageUrl)
  2408. .then((response) => {
  2409. if (!response.ok) {
  2410. throw new Error(`HTTP error! Status: ${response.status}`);
  2411. }
  2412. return response.blob();
  2413. })
  2414. .then((blob) => {
  2415. // Obtener el tamaño de la imagen en kilobytes
  2416. const imageSizeKB = blob.size / 1024;
  2417.  
  2418. // Verificar si el tamaño de la imagen es menor o igual a 20 KB
  2419. if (imageSizeKB >= 20) {
  2420. window.open(
  2421. `https://i.ytimg.com/vi/${enlace}/maxresdefault.jpg`,
  2422. 'popUpWindow',
  2423. 'height=500,width=400,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes'
  2424. );
  2425. // Crear una URL para la imagen
  2426. const imageUrlObject = URL.createObjectURL(blob);
  2427.  
  2428. // Crear un enlace para descargar la imagen
  2429. const enlaceDescarga = $cl('a');
  2430. enlaceDescarga.href = imageUrlObject;
  2431. const titleVideo = $e(
  2432. 'h1.style-scope.ytd-watch-metadata'
  2433. ).innerText;
  2434. enlaceDescarga.download = `${titleVideo}_maxresdefault.jpg`;
  2435.  
  2436. // Simular un clic en el enlace para iniciar la descarga
  2437. enlaceDescarga.click();
  2438.  
  2439. // Limpiar la URL del objeto después de la descarga
  2440. URL.revokeObjectURL(imageUrlObject);
  2441. } else {
  2442. console.log(
  2443. 'La imagen no excede los 20 KB. No se descargará.'
  2444. );
  2445. }
  2446. })
  2447. .catch((error) => {
  2448. alert('No found image');
  2449. console.error('Error al obtener la imagen:', error);
  2450. });
  2451. }
  2452. };
  2453. }
  2454. // for background image file photo higt quality
  2455. // const fileInput = $id('background_image');
  2456. // const backgroundDiv = $e('ytd-app');
  2457.  
  2458. // const storedImage = localStorage.getItem('backgroundImage');
  2459. // if (storedImage) {
  2460. // backgroundDiv.style = `background-size: contain; background-repeat: repeat; background-image: url(${storedImage}) !important`;
  2461. // }
  2462.  
  2463. // fileInput.addEventListener('change', (event) => {
  2464. // const file = event.target.files[0];
  2465. // if (file) {
  2466. // const reader = new FileReader();
  2467. // reader.onload = function (e) {
  2468. // const imageUrl = e.target.result;
  2469. // localStorage.setItem('backgroundImage', imageUrl);
  2470. // backgroundDiv.style.backgroundImage = `url(${imageUrl})`;
  2471. // };
  2472. // reader.readAsDataURL(file);
  2473. // }
  2474. // });
  2475.  
  2476.  
  2477. const externalLink = $e('.external_link');
  2478. if (externalLink != undefined) {
  2479. externalLink.onclick = () => {
  2480. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  2481. let enlace;
  2482. enlace = parametrosURL.get('v');
  2483. window.open(
  2484. `https://www.y2mate.com/es/convert-youtube/${enlace}`,
  2485. 'popUpWindow',
  2486. 'height=800,width=1000,left=50%,top=100,resizable=no,scrollbars=yes,toolbar=no,menubar=yes,location=no,directories=yes, status=no'
  2487. );
  2488. };
  2489. }
  2490. const viewExternalLink = $e('.view_external_link');
  2491. if (viewExternalLink != undefined) {
  2492. viewExternalLink.onclick = () => {
  2493. $e('video').click();
  2494. const parametrosURL = new URLSearchParams(window.location.search); // Url parametros
  2495. let enlace;
  2496. enlace = parametrosURL.get('v');
  2497. window.open(
  2498. `https://www.youtube.com/embed/${enlace}?rel=0&controls=2&color=white&iv_load_policy=3&showinfo=0&modestbranding=1&autoplay=1`
  2499. );
  2500. };
  2501. }
  2502. const viewPictureToPicture = $e(
  2503. '.video_picture_to_picture'
  2504. );
  2505. if (viewPictureToPicture != undefined) {
  2506. viewPictureToPicture.onclick = () => {
  2507. const video = $e('video');
  2508. // Verifica si el navegador admite Picture-in-Picture
  2509. if ('pictureInPictureEnabled' in document) {
  2510. // Verifica si el video aún no está en modo Picture-in-Picture
  2511. if (!document.pictureInPictureElement) {
  2512. // Intenta activar el modo Picture-in-Picture
  2513. video
  2514. .requestPictureInPicture()
  2515. .then(() => {
  2516. // El video está ahora en modo Picture-in-Picture
  2517. })
  2518. .catch((error) => {
  2519. console.error(
  2520. 'Error al activar el modo Picture-in-Picture:',
  2521. error
  2522. );
  2523. });
  2524. } else {
  2525. // video picture
  2526. }
  2527. } else {
  2528. alert('Picture-in-Picture not supported');
  2529. }
  2530. };
  2531.  
  2532. // Filtro de pantalla
  2533. if (formularioButtons != undefined) {
  2534. formularioButtons.addEventListener('input', function () {
  2535. if (
  2536. $e('#cinematics > div') != undefined ||
  2537. videoFull != undefined
  2538. ) {
  2539. $e('#ojosprotect').style.backgroundColor =
  2540. formularioButtons.value;
  2541. }
  2542. });
  2543. }
  2544. clearInterval(renderizarButtons);
  2545. }
  2546.  
  2547. const checked_updates = $e('.checked_updates');
  2548.  
  2549. if (checked_updates != undefined) {
  2550. checked_updates.onclick = () => {
  2551. window.open(
  2552. `https://update.gf.qytechs.cn/scripts/460680/Youtube%20Tools%20All%20in%20one%20local%20download%20mp3%20mp4%20HIGT%20QUALITY%20return%20dislikes%20and%20more.user.js`
  2553. );
  2554. };
  2555. }
  2556.  
  2557. const screenShotVideo = $e('.screenshot_video');
  2558. if (screenShotVideo != undefined) {
  2559. screenShotVideo.onclick = () => {
  2560. const video = $e('video');
  2561. const canvas = $cl('canvas');
  2562. canvas.width = video.videoWidth;
  2563. canvas.height = video.videoHeight;
  2564. const context = canvas.getContext('2d');
  2565. context.drawImage(video, 0, 0, canvas.width, canvas.height);
  2566. const imagenURL = canvas.toDataURL('image/png');
  2567. const enlaceDescarga = $cl('a');
  2568. enlaceDescarga.href = imagenURL;
  2569. const titleVideo = $e(
  2570. 'h1.style-scope.ytd-watch-metadata'
  2571. ).innerText;
  2572. enlaceDescarga.download = `${video.currentTime.toFixed(
  2573. 0
  2574. )}s_${titleVideo}.png`;
  2575. enlaceDescarga.click();
  2576. };
  2577. } else {
  2578. const containerButtons = $e('.containerButtons');
  2579.  
  2580. if (containerButtons != undefined) {
  2581. containerButtons.innerHTML = '';
  2582. }
  2583. }
  2584. clearInterval(renderizarButtons);
  2585. }
  2586.  
  2587.  
  2588.  
  2589.  
  2590. console.log('Scrip en ejecución by: DeveloperMDCM MDCM');
  2591. const HEADER_STYLE = 'color: #F00; font-size: 24px; font-family: sans-serif;';
  2592. const MESSAGE_STYLE = 'color: #00aaff; font-size: 16px; font-family: sans-serif;';
  2593. const CODE_STYLE = 'font-size: 14px; font-family: monospace;';
  2594.  
  2595. console.log(
  2596. '%cYoutube Tools Extension NEW UI\n' +
  2597. '%cRun %c(v2.3.3.2)\n' +
  2598. 'By: DeveloperMDCM.',
  2599. HEADER_STYLE,
  2600. CODE_STYLE,
  2601. MESSAGE_STYLE
  2602. );
  2603.  
  2604.  
  2605.  
  2606.  
  2607.  
  2608. // Add event listeners to all inputs
  2609. const inputs = $m('input');
  2610. inputs.forEach((input) => {
  2611. input.addEventListener('change', applySettings);
  2612. if (input.type === 'range') {
  2613. input.addEventListener('change', () => {
  2614. updateSliderValues();
  2615. applySettings();
  2616. });
  2617. }
  2618. });
  2619.  
  2620. // Export configuration
  2621.  
  2622. // Settings saved
  2623. // const settings = GM_getValue('ytSettingsMDCM', '{}');
  2624. // $id('config-data').value = settings;
  2625.  
  2626. $id('export-config').addEventListener('click', () => {
  2627. const settings = GM_getValue('ytSettingsMDCM', '{}');
  2628. $id('config-data').value = settings;
  2629. const configData = settings;
  2630. try {
  2631. JSON.parse(configData); // Validate JSON
  2632. GM_setValue('ytSettingsMDCM', configData);
  2633. alert('Configuration export successfully!');
  2634. } catch (e) {
  2635. alert('Invalid configuration data. Please check and try again.');
  2636. }
  2637. });
  2638. // Import configuration
  2639. $id('import-config').addEventListener('click', () => {
  2640. const configData = $id('config-data').value;
  2641. try {
  2642. JSON.parse(configData); // Validate JSON
  2643. GM_setValue('ytSettingsMDCM', configData);
  2644. alert('Configuration imported successfully!');
  2645. window.location.reload();
  2646. } catch (e) {
  2647. alert('Invalid configuration data. Please check and try again.');
  2648. }
  2649. });
  2650. panel.style.display = 'none'; // Ensure panel is hidden on load
  2651.  
  2652. // Stats
  2653.  
  2654. // Format time
  2655. function formatTime(seconds) {
  2656. if (isNaN(seconds)) return '0h 0m 0s';
  2657. seconds = Math.floor(seconds);
  2658. const h = Math.floor(seconds / 3600);
  2659. const m = Math.floor((seconds % 3600) / 60);
  2660. const s = seconds % 60;
  2661. return `${h}h ${m}m ${s}s`;
  2662. }
  2663.  
  2664. function updateUI() {
  2665. $id('total-time').textContent = formatTime(usageTime);
  2666. $id('video-time').textContent = formatTime(videoTime);
  2667. $id('shorts-time').textContent = formatTime(shortsTime);
  2668.  
  2669. const maxTime = 86400; // 24 hours
  2670. $id('usage-bar').style.width =
  2671. `${(usageTime / maxTime) * 100}%`;
  2672. $id('video-bar').style.width =
  2673. `${(videoTime / maxTime) * 100}%`;
  2674. $id('shorts-bar').style.width =
  2675. `${(shortsTime / maxTime) * 100}%`;
  2676. }
  2677.  
  2678. function detectContentType(videoElement) {
  2679. if (/\/shorts\//.test(window.location.pathname)) return 'shorts';
  2680.  
  2681. let parent = videoElement;
  2682. while ((parent = parent.parentElement) !== null) {
  2683. if (parent.classList.contains('shorts-container') ||
  2684. parent.classList.contains('reel-video') ||
  2685. parent.tagName === 'YTD-REEL-VIDEO-RENDERER') {
  2686. return 'shorts';
  2687. }
  2688. }
  2689.  
  2690.  
  2691. if (videoElement.closest('ytd-watch-flexy') ||
  2692. videoElement.closest('#primary-inner')) {
  2693. return 'video';
  2694. }
  2695. if (videoElement.closest('ytd-thumbnail') ||
  2696. videoElement.closest('ytd-rich-item-renderer')) {
  2697. return 'video';
  2698. }
  2699.  
  2700. return null;
  2701. }
  2702.  
  2703. function findActiveVideo() {
  2704. const videos = document.querySelectorAll('video');
  2705. for (const video of videos) {
  2706. if (!video.paused && !video.ended && video.readyState > 2) {
  2707. return video;
  2708. }
  2709. }
  2710. return null;
  2711. }
  2712.  
  2713. const observer = new MutationObserver(() => {
  2714. const newVideo = findActiveVideo();
  2715. if (newVideo !== activeVideo) {
  2716. activeVideo = newVideo;
  2717. if (activeVideo) {
  2718. activeType = detectContentType(activeVideo);
  2719. console.log('Contenido detectado:', activeType);
  2720. }
  2721. }
  2722. });
  2723.  
  2724.  
  2725. setInterval(() => {
  2726. const now = Date.now();
  2727. const delta = (now - lastUpdate) / 1000;
  2728. if (document.visibilityState === 'visible') {
  2729. usageTime += delta;
  2730. }
  2731.  
  2732. if (activeVideo && !activeVideo.paused) {
  2733. if (activeType === 'video') {
  2734. videoTime += delta;
  2735. } else if (activeType === 'shorts') {
  2736. shortsTime += delta;
  2737. }
  2738. }
  2739.  
  2740. lastUpdate = now;
  2741. updateUI();
  2742. }, UPDATE_INTERVAL);
  2743.  
  2744.  
  2745.  
  2746. window.addEventListener('beforeunload', () => {
  2747. GM_setValue(STORAGE.USAGE, Math.floor(usageTime));
  2748. GM_setValue(STORAGE.VIDEO, Math.floor(videoTime));
  2749. GM_setValue(STORAGE.SHORTS, Math.floor(shortsTime));
  2750. });
  2751.  
  2752. // Inicialización
  2753. observer.observe(document.body, {
  2754. childList: true,
  2755. subtree: true,
  2756. attributes: true
  2757. });
  2758. updateUI();
  2759.  
  2760. // end stats
  2761.  
  2762. // Load saved settings
  2763. // Visible element DOM
  2764. function checkElement(selector, callback) {
  2765. const interval = setInterval(() => {
  2766. if ($e(selector)) {
  2767. clearInterval(interval);
  2768.  
  2769. callback();
  2770. }
  2771. }, 100);
  2772. }
  2773.  
  2774. checkElement('ytd-topbar-menu-button-renderer', loadSettings);
  2775.  
  2776. })();

QingJ © 2025

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