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

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

当前为 2024-09-18 提交的版本,查看 最新版本

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

QingJ © 2025

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