// ==UserScript== // @name All-in-One Video Downloader – HD (YouTube, TikTok, Instagram, X & More) // @name:ar مُحمِّل فيديو متكامل – HD (يوتيوب، تيك توك، إنستغرام، إكس وغيرها) // @name:bg Универсален видеоизтегляч – HD (YouTube, TikTok, Instagram, X и др.) // @name:cs Univerzální stahovač videí – HD (YouTube, TikTok, Instagram, X a další) // @name:da Alt-i-ét-video-downloader – HD (YouTube, TikTok, Instagram, X m.m.) // @name:de All-in-One-Video-Downloader – HD (YouTube, TikTok, Instagram, X u. a.) // @name:el Ολοκληρωμένη λήψη βίντεο – HD (YouTube, TikTok, Instagram, X και άλλα) // @name:en All-in-One Video Downloader – HD (YouTube, TikTok, Instagram, X & More) // @name:eo Ĉio-en-unu video-elŝutilo – HD (YouTube, TikTok, Instagram, X kaj pli) // @name:es Descargador de vídeo todo en uno – HD (YouTube, TikTok, Instagram, X y más) // @name:es-419 Descargador de video todo en uno – HD (YouTube, TikTok, Instagram, X y más) // @name:fi Kaikki yhdessä -videolataaja – HD (YouTube, TikTok, Instagram, X jne.) // @name:fr Téléchargeur vidéo tout-en-un – HD (YouTube, TikTok, Instagram, X et plus) // @name:fr-CA Téléchargeur de vidéos tout-en-un – HD (YouTube, TikTok, Instagram, X et plus) // @name:he מוריד וידאו הכול-באחד – HD (YouTube, TikTok, Instagram, X ועוד) // @name:hr Sve-u-jednom preuzimanje videa – HD (YouTube, TikTok, Instagram, X i više) // @name:hu Minden-egyben videóletöltő – HD (YouTube, TikTok, Instagram, X és más) // @name:id Pengunduh video serba ada – HD (YouTube, TikTok, Instagram, X, dll.) // @name:it Scaricatore video tutto-in-uno – HD (YouTube, TikTok, Instagram, X e altro) // @name:ja オールインワン動画ダウンローダー – HD(YouTube、TikTok、Instagram、X など) // @name:ka ყველაფერი-ერთში ვიდეოს ჩამოტვირთვა – HD (YouTube, TikTok, Instagram, X და სხვა) // @name:ko 올인원 동영상 다운로더 – HD(YouTube, TikTok, Instagram, X 등) // @name:nb Alt-i-ett-videonedlaster – HD (YouTube, TikTok, Instagram, X m.m.) // @name:nl Alles-in-één video-downloader – HD (YouTube, TikTok, Instagram, X en meer) // @name:pl Uniwersalny pobieracz wideo – HD (YouTube, TikTok, Instagram, X i inne) // @name:pt-BR Baixador de vídeo tudo-em-um – HD (YouTube, TikTok, Instagram, X e mais) // @name:ro Descărcător video totul-într-unul – HD (YouTube, TikTok, Instagram, X și altele) // @name:ru Универсальный загрузчик видео – HD (YouTube, TikTok, Instagram, X и др.) // @name:sv Allt-i-ett-videonedladdare – HD (YouTube, TikTok, Instagram, X m.m.) // @name:th ดาวน์โหลดวิดีโอครบในที่เดียว – HD (YouTube, TikTok, Instagram, X และอื่นๆ) // @name:tr Hepsi bir arada video indirici – HD (YouTube, TikTok, Instagram, X ve daha fazlası) // @name:uk Універсальний завантажувач відео – HD (YouTube, TikTok, Instagram, X тощо) // @name:ug بارلىق ئىقتىدار بىر يەردە: HD ۋىدىئو چۈشۈرگۈچ (YouTube، TikTok، Instagram، X ۋە باشقىلار) // @name:vi Trình tải video tất cả trong một – HD (YouTube, TikTok, Instagram, X và hơn thế nữa) // @name:zh-CN 多合一视频下载器(支持:YouTube, TikTok, Instagram等) // @name:zh-TW 多合一視頻下載器(支援:YouTube, TikTok, Instagram等) // @description An all-in-one, fast, and free HD video downloader. Supports video downloads from YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (formerly Twitter), and more. Enjoy seamless, high-quality downloads with no watermarks. // @description:ar أداة شاملة وسريعة ومجانية لتحميل مقاطع الفيديو بدقة عالية. يدعم تحميل مقاطع الفيديو من يوتيوب، تيك توك، Douyin، إنستغرام، ثريدز، XiaoHongShu، إكس (تويتر سابقًا)، والمزيد. استمتع بتحميلات عالية الجودة بدون علامات مائية. // @description:bg Всичко в едно, бързо и безплатно изтегляне на видео с висока резолюция. Поддържа изтегляне на видеа от YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (бивш Twitter) и други. Насладете се на безпроблемни, висококачествени изтегляния без водни знаци. // @description:cs Vše v jednom, rychlý a bezplatný downloader videí ve vysoké kvalitě. Podporuje stahování videí z YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (dříve Twitter) a dalších. Užijte si plynulé, kvalitní stahování bez vodoznaků. // @description:da En alt-i-en, hurtig og gratis HD video downloader. Understøtter video downloads fra YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (tidligere Twitter) og mere. Nyd problemfri, høj kvalitet downloads uden vandmærker. // @description:de Ein All-in-One, schneller und kostenloser HD-Video-Downloader. Unterstützt das Herunterladen von Videos von YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (ehemals Twitter) und mehr. Genießen Sie nahtlose, hochqualitative Downloads ohne Wasserzeichen. // @description:el Ένας ολοκληρωμένος, γρήγορος και δωρεάν downloader HD βίντεο. Υποστηρίζει λήψη βίντεο από YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (πρώην Twitter) και άλλα. Απολαύστε απρόσκοπτες, υψηλής ποιότητας λήψεις χωρίς υδατογραφήματα. // @description:en An all-in-one, fast, and free HD video downloader. Supports video downloads from YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (formerly Twitter), and more. Enjoy seamless, high-quality downloads with no watermarks. // @description:eo Ĉio-en-unu, rapida kaj senpaga HD-video-elŝutilo. Subtenas video-elŝutojn de YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (antaŭe Twitter), kaj aliaj. Ŝatu seninterrompajn, altkvalitajn elŝutojn sen akvamaĵoj. // @description:es Un descargador de video todo en uno, rápido y gratuito en HD. Admite descargas de videos de YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (anteriormente Twitter) y más. Disfruta de descargas de alta calidad sin marcas de agua. // @description:fi Kaikki yhdessä, nopea ja ilmainen HD-videoiden lataaja. Tukee videoiden lataamista YouTubesta, TikTokista, Douyinista, Instagramista, Threadsista, XiaoHongShusta, X:stä (entinen Twitter) ja muista. Nauti saumatonta, korkealaatuista lataamista ilman vesileimoja. // @description:fr Un téléchargeur vidéo HD tout-en-un, rapide et gratuit. Prend en charge les téléchargements de vidéos depuis YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (anciennement Twitter) et plus encore. Profitez de téléchargements fluides et de haute qualité sans filigranes. // @description:fr-CA Un téléchargeur vidéo HD tout-en-un, rapide et gratuit. Prend en charge les téléchargements de vidéos depuis YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (anciennement Twitter) et plus encore. Profitez de téléchargements fluides et de haute qualité sans filigranes. // @description:he מנוע הורדות וידאו HD מהיר, חינמי ומקיף. תומך בהורדת וידאו מיוטיוב, טיקטוק, אינסטגרם, Threads, XiaoHongShu, TED, X (בעבר טוויטר) ועוד. תהנה מהורדות באיכות גבוהה ללא סימני מים. // @description:hr Svi-u-jednom, brzi i besplatni HD downloader za video. Podržava preuzimanje videa s YouTubea, TikToka, Instagrama, Threads, XiaoHongShu, TED, X (bivši Twitter) i još mnogo toga. Uživajte u besprijekornim, visokokvalitetnim preuzimanjima bez vodmarks. // @description:hu Egy minden-egyben, gyors és ingyenes HD videó letöltő. Támogatja a videók letöltését YouTube-ról, TikTok-ról, Instagram-ról, Threads, XiaoHongShu, TED, X (régen Twitter) és másról. Élvezze a zökkenőmentes, magas minőségű letöltéseket vízjel nélkül. // @description:id Downloader video HD serba ada, cepat, dan gratis. Mendukung unduhan video dari YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (sebelumnya Twitter), dan banyak lagi. Nikmati unduhan berkualitas tinggi tanpa tanda air. // @description:it Un downloader video HD completo, veloce e gratuito. Supporta il download di video da YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (precedentemente Twitter) e altri. Goditi download fluidi e di alta qualità senza filigrane. // @description:ja YouTube の視聴体験を向上させるための高速で無料な HD 動画ダウンローダー。YouTube、TikTok、Douyin、Instagram、Threads、XiaoHongShu、X(旧 Twitter)などからの動画ダウンロードをサポート。シームレスで高品質なダウンロードをウォーターマークなしでお楽しみください。 // @description:ka ყველაფერი ერთში, სწრაფი და უფასო HD ვიდეო ჩამოტვირთვა. მხარს უჭერს ვიდეოს ჩამოტვირთვას YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (ყოფილი Twitter) და სხვა პლატფორმებიდან. დატკბით უარყოფითი ნიშნების გარეშე, უმაღლესი ხარისხის ჩამოტვირთვებით. // @description:ko YouTube 시청 경험을 향상시키는 모든 기능을 갖춘, 빠르고 무료인 HD 비디오 다운로드기. YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X(이전 Twitter) 등에서 비디오 다운로드를 지원합니다. 워터마크 없이 원활한 고품질 다운로드를 즐기세요. // @description:nb En alt-i-en, rask og gratis HD video nedlaster. Støtter video nedlastinger fra YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (tidligere Twitter), og mer. Nyt sømløse, høy kvalitet nedlastinger uten vannmerker. // @description:nl Een alles-in-één, snelle en gratis HD-video downloader. Ondersteunt video-downloads van YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (voorheen Twitter) en meer. Geniet van naadloze, hoogwaardige downloads zonder watermerken. // @description:pl Jedno w jednym, szybki i darmowy pobieracz wideo HD. Obsługuje pobieranie wideo z YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (dawniej Twitter) i innych. Ciesz się płynne, wysokiej jakości pobieranie bez znaków wodnych. // @description:pt-BR Um downloader de vídeo HD completo, rápido e gratuito. Suporta downloads de vídeos do YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (anteriormente Twitter) e muito mais. Aproveite downloads de alta qualidade sem marcas d'água. // @description:ro Un downloader video HD rapid și gratuit, totul într-un singur pachet. Suportă descărcarea de videoclipuri de pe YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (fost Twitter) și altele. Bucurați-vă de descărcări de înaltă calitate fără filigrane. // @description:ru Все-в-одном, быстрый и бесплатный HD видеозагрузчик. Поддерживает загрузку видео с YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (бывший Twitter) и других. Наслаждайтесь безупречными загрузками высокого качества без водяных знаков. // @description:sv En allt-i-ett, snabb och gratis HD-video nedladdare. Stöder video nedladdningar från YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (tidigare Twitter) och mer. Njut av sömlösa, högkvalitativa nedladdningar utan vattenmärken. // @description:th เครื่องมือดาวน์โหลดวิดีโอ HD ที่รวดเร็วและฟรีแบบครบวงจร รองรับการดาวน์โหลดวิดีโอจาก YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (เดิม Twitter) และอื่นๆ เพลิดเพลินกับการดาวน์โหลดที่มีคุณภาพสูงโดยไม่มีลายน้ำ // @description:tr Birçok platformdan video indirmenizi destekleyen, hızlı ve ücretsiz HD video indirme aracıdır. YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (eski Twitter) ve daha fazlasını destekler. Su işareti olmadan kesintisiz yüksek kaliteli indirmelerin keyfini çıkarın. // @description:uk Всі в одному, швидкий та безкоштовний HD відео-завантажувач. Підтримує завантаження відео з YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (колишній Twitter) та інших. Насолоджуйтесь безперешкодними високоякісними завантаженнями без водяних знаків. // @description:ug YouTube كۆرۈش تەجرىبەڭىزنى ياخشىلايدىغان، تىز ۋە ھەقسىز HD ۋىدىئو چۈشۈرگۈچى. يۇتۇب، تيك توك، دۇيىن، ئىنستاگرام، Threads، XiaoHongShu، X (ئالدىنقى Twitter) ۋە باشقا پلاتفورمالاردىن ۋىدىئو چۈشۈرۈشنى قوللايدۇ. سۇ ئىشاراتسىز ئېغىزدىن سۈپەتلىك چۈشۈرۈشتىن لەززەتلىنىڭ. // @description:vi Trình tải video HD tất cả trong một, nhanh chóng và miễn phí. Hỗ trợ tải video từ YouTube, TikTok, Douyin, Instagram, Threads, XiaoHongShu, TED, X (trước đây là Twitter) và nhiều nền tảng khác. Thưởng thức tải xuống chất lượng cao mượt mà mà không có watermark. // @description:zh-CN 一款多合一、快速且免费的在线视频下载器。支持从 YouTube、TikTok、抖音、Instagram、Threads、小红书、X(Twitter)等平台下载视频。享受无水印、高质量、流畅便捷的下载体验 // @description:zh-TW 一款多合一、快速且免費的線上視頻下載器。支援從 YouTube、TikTok、抖音、Instagram、Threads、小紅書、X(Twitter)等平台下載視頻。享受無水印、高質量、流暢便捷的下載體驗 // @namespace AllInOneDownloader_Daniel // @version 1.0.9 // @author Daniel // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAAwCAYAAABe6Vn9AAACZElEQVR4AeyZbVKDMBCGgYuJ/9WT2CNoqx6hnkT9T72YuA+WDg0M2SSblnFwWCfNfuR9EhqatiqM/+72bX3/3jZirccaYo2HL8yByrLYishazHfVx1hfXJDfHEhG18BIWHeFxHYJvn85gHxjZvWvQFmn16D4ukIGk5i1xLpCWafXoPi6QgaTmLXEukJZp9eg+LpCBpOYtYR6hTi7yPnGe84JVSs1feemlrG1ddVAx7OL+cd9jdDj2JpQ+wOeatTwIPVEqleobYuXcB3zGVqvjH2rjVUDfW3KQ3kFKGAY2xyIgh+bcndJqFAYNKpXiGDsUlAxMOgLBiIpN1QsDNqigEjMBZUCg65oIJKtoVJh0JQERAErKAsY9CQDUSQVygoGLSZAFIqFsoRBhxkQxUKheKaFPDQZw2emQAymhQKGWHIszRwIcQhFMO0pw0fMlC+1rwN62Lc7zblkLsY9syAY4a5A+vAN+8mdq63xwUDNikb795sOr6NNziyjH7AQDgAmhQ9sAPRJ+3QBQ+6pI7IBg4A/VzQia4zSEIbAoQMA7POxvHU3AGLJGcYntp+6Wy6xyFk6AhF61jnxghhiJ1xJXeZAqEEotzLtKcsFw1hZgCjMrQwUBkBvcp83ABOTw7IBIRYoDIDepF/9/YDEBl9qoODKV0pYIlC3vcuuWMqcHMTca9a/OCB5Zn3327s8t0bfNPn8iwP6KYrTqoi40ftt6C8m/iRnoveKXbJ5bPudUTaUG1fK0E/b9S8OSATWArIVsQ1tMfea9S8RyAUIel3Jm2z0xguqsKzgt4oPjv8BCgbZ6l9/AQAA//9HnEu0AAAABklEQVQDAI1HmgBXKvxdAAAAAElFTkSuQmCC // @include https://www.ted.com/* // @include https://*.youtube.com/* // @include https://x.com/* // @include https://twitter.com/* // @include https://www.threads.com/* // @include https://www.instagram.com/reels/* // @include https://www.tikTok.com/* // @include https://www.douyin.com/* // @include https://www.xiaohongshu.com/* // @include https://*.googlevideo.com/* // @include https://*.tiktokcdn.com/* // @include https://*.douyinvod.com/* // @include https://*.fbcdn.net/* // @include https://video.twimg.com/* // @include https://*.zjcdn.com/* // @include https://*.snssdk.com/* // @include https://*.tiktokv.com/* // @include https://*.douyinstatic.com/* // @include https://*.xhscdn.com/* // @include https://*.amemv.com/* // @include https://*.tikwm.com/* // @include https://*.tiktokcdn-eu.com/* // @include https://*.tiktokcdn-us.com/* // @include https://*.douyinpic.com/* // @include https://*.douyinmusicpromotion.com/* // @include https://*.cdninstagram.com/* // @connect googlevideo.com // @connect tiktokcdn.com // @connect snssdk.com // @connect douyinvod.com // @connect tiktokv.com // @connect fbcdn.net // @connect zjcdn.com // @connect twimg.com // @connect douyinstatic.com // @connect xhscdn.com // @connect amemv.com // @connect tikwm.com // @connect tiktokcdn-eu.com // @connect tiktokcdn-us.com // @connect douyinpic.com // @connect douyinmusicpromotion.com // @connect cdninstagram.com // @noframes // @license MIT // @run-at document-start // @antifeature referral-link // @grant GM_openInTab // @grant GM.openInTab // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_download // @grant unsafeWindow // @downloadURL https://update.greasyfork.icu/scripts/563321/All-in-One%20Video%20Downloader%20%E2%80%93%20HD%20%28YouTube%2C%20TikTok%2C%20Instagram%2C%20X%20%20More%29.user.js // @updateURL https://update.greasyfork.icu/scripts/563321/All-in-One%20Video%20Downloader%20%E2%80%93%20HD%20%28YouTube%2C%20TikTok%2C%20Instagram%2C%20X%20%20More%29.meta.js // ==/UserScript== (function () { 'use strict'; /*! * Copyright (c) 2026 - 2026, Daniel. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ const CommonUtils = { getSupportedLang: function() { const lang = navigator.language || navigator.userLanguage; const supportedLanguages = { "en": "en", "es": "es", "fr": "fr", "pt": "pt", "ru": "ru", "ja": "ja", "de": "de", "ko": "ko", "it": "it", "id": "id", "tr": "tr", "pl": "pl", "uk": "uk", "nl": "nl", "vi": "vi", "th": "th", "ar": "ar", "fa": "fa", "hi": "hi", "ms": "ms", "zh-CN": "zh-CN", "zh-TW": "zh-TW" }; const langCode = lang.split("-")[0]; if (langCode === "zh") { return lang === "zh-CN" ? "zh-CN" : "zh-TW"; } return supportedLanguages[langCode] || "en"; }, openInTab: function(url, options = { "active": true, "insert": true, "setParent": true }) { if (typeof GM_openInTab === "function") { GM_openInTab(url, options); } else { GM.openInTab(url, options); } }, genrateDownloadSvg: function(color = "#FFF", width = 25, height = 25) { let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("t", "1768806429307"); svg.setAttribute("class", "icon"); svg.setAttribute("viewBox", "0 0 1024 1024"); svg.setAttribute("version", "1.1"); svg.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svg.setAttribute("p-id", "21520"); svg.setAttribute("width", width); svg.setAttribute("height", height); let path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("d", "M684.5 512H573.1V389.8c0-11.2-9.1-20.4-20.4-20.4h-81.5c-11.3 0-20.4 9.1-20.4 20.4v122.4l-112.4 0.6c-4 0-7.1 2.3-8.5 5.5 0 0.1-0.1 0.1-0.1 0.2-0.3 0.6-0.3 1.3-0.4 2-0.1 0.6-0.3 1.2-0.2 1.8 0 0.1-0.1 0.3-0.1 0.4 0 0.4 0.2 0.7 0.3 1.1 0.2 0.8 0.3 1.6 0.7 2.4 0.2 0.4 0.4 0.7 0.6 1 0.3 0.6 0.6 1.2 1 1.7l168.2 188c0.4 0.4 0.8 0.6 1.2 1 0.2 0.2 0.3 0.5 0.6 0.7 0.2 0.2 0.5 0.2 0.8 0.4 0.7 0.4 1.4 0.7 2.1 1 0.2 0.1 0.5 0.2 0.7 0.2 2.9 0.9 6 0.6 8.3-1.3 0.5-0.4 0.8-1.1 1.2-1.6 0.3-0.2 0.6-0.4 0.9-0.7l175.2-187.8c0.5-0.6 0.8-1.3 1.2-1.9 0.2-0.3 0.4-0.5 0.5-0.9 0.4-0.8 0.6-1.6 0.7-2.3 0.1-0.4 0.3-0.6 0.3-1v-1c0.6-5.4-3.6-9.7-9.1-9.7zM471.3 349.1h81.5c11.3 0 20.4-9.1 20.4-20.4v-20.4c0-11.2-9.1-20.4-20.4-20.4h-81.5c-11.3 0-20.4 9.1-20.4 20.4v20.4c0 11.3 9.1 20.4 20.4 20.4zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m0 814.6c-202.4 0-366.5-164.1-366.5-366.6 0-202.4 164.1-366.5 366.5-366.5S878.5 309.6 878.5 512 714.4 878.6 512 878.6z"); path.setAttribute("fill", color); svg.appendChild(path); return svg; }, formatBytes: function(bytes, decimals = 2) { const size = Number(bytes); if (!Number.isFinite(size) || size < 0) { return "0 KB"; } const kb = 1024; const mb = kb * 1024; const gb = mb * 1024; if (size >= gb) { return `${(size / gb).toFixed(decimals)} GB`; } if (size >= mb) { return `${(size / mb).toFixed(decimals)} MB`; } return `${(size / kb).toFixed(decimals)} KB`; } }; const YouTubeDownloader = { downloadVideo: function() { const url = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=" + encodeURIComponent(window.location.href); CommonUtils.openInTab(url); }, genrate: function() { return new Promise((resolve) => { const buttonId = "all-in-one-downloader"; const boxContainer = document.createElement("div"); boxContainer.className = "ytp-button"; boxContainer.id = buttonId; boxContainer.setAttribute("style", `position: relative;display: inline-block;width: 48px;height: 100%;`); const boxInner = document.createElement("div"); boxInner.setAttribute("style", `position: absolute;width: 100%;height: 100%; `); const boxActiveButton = document.createElement("button"); boxActiveButton.setAttribute("style", `background-color: transparent;width: 100%;height: 100%;outline: none;flex: 1 1 0%;display: flex;-webkit-box-align: center;align-items: center;-webkit-box-pack: center;justify-content: center;border: none;padding: 0px;cursor: pointer;`); boxContainer.appendChild(boxInner); boxInner.appendChild(boxActiveButton); boxActiveButton.appendChild(CommonUtils.genrateDownloadSvg("#FFF")); boxContainer.addEventListener("click", () => { this.downloadVideo(); }); const genrateHtml = () => { const player = document.querySelector("#player-container-outer .html5-video-player"); if (player) { const rightControls = player.querySelector(".ytp-right-controls"); if (rightControls) { rightControls.prepend(boxContainer); } } }; const interval = setInterval(() => { if (!document.querySelector("#" + buttonId)) { genrateHtml(); } else { resolve(); clearInterval(interval); } }, 777); }); }, genrateShorts: function() { const genrateHtml = () => { if (window.location.href.indexOf("/shorts/") != -1) { const navigationButtonDown = document.querySelector("#navigation-button-down"); if (navigationButtonDown) { const download = document.createElement("div"); download.style.cursor = "pointer"; download.setAttribute("style", "cursor:pointer;display: flex;justify-content: center;align-items: center;"); download.id = "script_download_shorts"; download.className = "navigation-button style-scope ytd-shorts"; navigationButtonDown.after(download); download.appendChild(CommonUtils.genrateDownloadSvg("#3e3e3e", 45, 45)); download.addEventListener("click", () => { this.downloadVideo(); }); } } }; setInterval(() => { if (!document.querySelector("#script_download_shorts")) { genrateHtml(); } }, 800); }, run: function() { this.genrate(); this.genrateShorts(); }, start: function() { const isRun = /youtube\.com/.test(window.location.host); if (isRun) { this.run(); } } }; const TiktokDownloader = { downloadVideo: function(playId) { if (playId) { const url = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=https%3A%2F%2Fwww.tiktok.com%2F%40_%2Fvideo/" + playId; CommonUtils.openInTab(url); } }, findAncestorByClass: function(element, className, maxDepth = Infinity) { let current = element; let depth = 0; while (current && depth < maxDepth) { current = current.parentElement; depth++; if (current && current.classList.contains(className)) { return current; } } return null; }, extractLastDashNumber: function(str) { if (!str) return null; const match = str.match(/-(\d+)$/); return match ? match[1] : null; }, genrate: function() { const randomId = Math.floor(1e5 + Math.random() * 9e5); GM_addStyle(` .sc-download-` + randomId + `{ cursor:pointer; justify-content:center; align-items:center; width:40px; height:40px; z-index:99999; position:absolute; right:55px; top:10px; border-radius:50%; display: flex; border-radius:50%; } .sc-download-` + randomId + `::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(90deg,red, orange, yellow, green, cyan, blue, violet, red); background-size: 200% 200%; opacity: 0; transition: opacity .25s; -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; } .sc-download-` + randomId + `:hover::before { opacity: 1; animation: rainbowMove 3s linear infinite; } @keyframes rainbowMove { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } } `); setInterval(() => { document.querySelectorAll("video").forEach((element, index) => { if (element.getAttribute("src")) { const parentNode = element.parentNode; if (!parentNode.querySelector("*[x-add='true']")) { const downloadElement = document.createElement("div"); downloadElement.setAttribute("x-add", "true"); downloadElement.classList.add("sc-download-" + randomId); downloadElement.appendChild(CommonUtils.genrateDownloadSvg("#FFF")); downloadElement.style.cursor = "pointer"; parentNode.appendChild(downloadElement); downloadElement.addEventListener("click", () => { const container = this.findAncestorByClass(parentNode, "xgplayer-container", 3); if (container && container.getAttribute("id")) { const playId = this.extractLastDashNumber(container.getAttribute("id")); if (playId) this.downloadVideo(playId); } }); } } }); }, 1e3); }, start: function() { const isRun = /tiktok\.com/.test(window.location.host); if (isRun) { this.genrate(); } } }; const ThreadsDownloader = { downloadVideo: function(url) { const openUrl = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=" + encodeURIComponent(url); CommonUtils.openInTab(openUrl); }, run: function() { setInterval(() => { document.querySelectorAll("*[data-pressable-container='true']:not([detectvs='true'])").forEach((element) => { if (element.querySelector("video") === null) { return; } element.setAttribute("detectvs", "true"); const buttons = element.querySelectorAll("*[role='button']"); const btnLen = buttons.length; if (btnLen <= 1) { return; } const lastButton = buttons[buttons.length - 1]; const shareButton = lastButton.parentElement; const downloadButton = shareButton.cloneNode(false); downloadButton.appendChild(CommonUtils.genrateDownloadSvg("#505050", 20, 20)); downloadButton.style.cursor = "pointer"; shareButton.insertAdjacentElement("afterend", downloadButton); downloadButton.addEventListener("click", (e) => { const links = element.querySelectorAll("a[role='link']"); e.stopPropagation(); e.preventDefault(); let link = ""; for (let i = 0; i < links.length; i++) { if (links[i].getAttribute("href").indexOf("/post/") != -1) { link = "https://www.threads.com" + links[i].getAttribute("href"); } } if (!!link) { this.downloadVideo(link); } else { this.downloadVideo(window.location.href); } }); }); }, 777); }, start: function() { const isYoutube = /threads\.com/.test(window.location.host); if (isYoutube) { this.run(); } } }; const TwitterDownloader = { svg: ` `, showSensitive: true, isTweetdeck: () => window.location.host.includes("tweetdeck"), extractStatusId: (url) => url ? (url.match(/\/status\/(\d+)/) || [null, null])[1] : null, downloadVideo: function(statusIds) { const url = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=https%3A%2F%2Fx.com/_/status/" + statusIds; CommonUtils.openInTab(url); }, addButtonTo: function(article) { if (article.dataset.detected) return; article.dataset.detected = "true"; const statusIds = Array.from(article.querySelectorAll('a[href*="/status/"]')).map((el) => this.extractStatusId(el.href)).filter((id) => id); if (statusIds.length === 0) return; const mediaSelector = [ 'div[role="progressbar"]', 'button[data-testid="playButton"]', 'div[data-testid="videoComponent"]', 'a[href="/settings/content_you_see"]', "div.media-image-container", "div.media-preview-container", 'div[aria-labelledby]>div:first-child>div[role="button"][tabindex="0"]' ]; const hasMedia = article.querySelector(mediaSelector.join(",")); if (hasMedia) { const btnGroup = article.querySelector('div[role="group"]:last-of-type, ul.tweet-actions, ul.tweet-detail-actions'); if (btnGroup) { const btnShare = Array.from(btnGroup.querySelectorAll(":scope>div>div, li.tweet-action-item>a, li.tweet-detail-action-item>a")).pop().parentNode; const btnDownload = btnShare.cloneNode(true); btnDownload.style.marginLeft = "10px"; btnDownload.style.cursor = "pointer"; btnDownload.querySelector("button")?.removeAttribute("disabled"); const svgContainer = this.isTweetdeck() ? btnDownload.firstElementChild : btnDownload.querySelector("svg"); if (svgContainer) { if (this.isTweetdeck()) { svgContainer.innerHTML = `${this.svg}`; svgContainer.removeAttribute("rel"); btnDownload.classList.replace("pull-left", "pull-right"); } else { svgContainer.innerHTML = this.svg; } } btnGroup.insertBefore(btnDownload, btnShare.nextSibling); btnDownload.onclick = () => { this.downloadVideo(statusIds); }; if (this.showSensitive) { article.querySelector('div[aria-labelledby] div[role="button"][tabindex="0"]:not([data-testid]) > div[dir] > span > span')?.click(); } } } }, addButtonToMedia: function(listitems) { listitems.forEach((li) => { if (li.dataset.detected) return; li.dataset.detected = "true"; const statusElement = li.querySelector('a[href*="/status/"]'); const statusId = statusElement ? this.extractStatusId(statusElement.href) : null; if (!statusId) return; const btnDownload = document.createElement("div"); btnDownload.style.cursor = "pointer"; btnDownload.innerHTML = `
${this.svg}
`; li.appendChild(btnDownload); btnDownload.onclick = () => { this.downloadVideo(statusId); }; }); }, detect: function(node) { const article = node.tagName === "ARTICLE" && node || node.tagName === "DIV" && (node.querySelector("article") || node.closest("article")); if (article) { this.addButtonTo(article); } const listitems = node.tagName === "LI" && node.getAttribute("role") === "listitem" ? [node] : node.tagName === "DIV" && node.querySelectorAll('li[role="listitem"]'); if (listitems) { this.addButtonToMedia(listitems); } }, run: function() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { this.detect(node); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); }, start: function() { const isRun = /twitter|x\.com/.test(window.location.host); if (isRun) { this.run(); } } }; const InstagramDownloader = { downloadVideo: function() { const url = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=" + encodeURIComponent(window.location.href); CommonUtils.openInTab(url); }, run: function() { const interval = setInterval(() => { const toolbar = document.querySelector("div[role='toolbar']"); if (toolbar) { clearInterval(interval); const downloadDiv = toolbar.firstElementChild.cloneNode(); downloadDiv.style.cursor = "pointer"; downloadDiv.appendChild(CommonUtils.genrateDownloadSvg("#000", 30, 30)); downloadDiv.addEventListener("click", () => { this.downloadVideo(); }); toolbar.appendChild(downloadDiv); } }, 777); }, start: function() { const isRun = /instagram\.com/.test(window.location.host); if (isRun) { this.run(); } } }; const DouyinDownloader = { downloadVideo: function() { CommonUtils.openInTab("https://www.tool77.com/zh-CN/v/downloader?url=" + encodeURIComponent(window.location.href)); }, genrate: function() { const controllers = document.querySelectorAll(".xg-inner-controls:not([downloaderx='true'])"); if (controllers.length === 0) return; controllers.forEach((controller) => { controller.setAttribute("downloaderx", "true"); const rightGrid = controller.querySelector(".xg-right-grid"); if (rightGrid) { const fullscreen = rightGrid.querySelector(".xgplayer-fullscreen"); if (fullscreen) { const donwload = fullscreen.cloneNode(false); donwload.style.display = "flex"; donwload.style.alignItems = "center"; donwload.style.justifyContent = "center"; donwload.style.margin = "0 7px"; donwload.appendChild(CommonUtils.genrateDownloadSvg("#FFF", 20, 20)); rightGrid.before(donwload); donwload.addEventListener("click", () => { this.downloadVideo(); }); } } }); }, start: function() { const isRun = /douyin\.com/.test(window.location.host); if (isRun) { setInterval(() => { this.genrate(); }, 777); } } }; const XiaoHongShuDownloader = { downloadVideo: function() { CommonUtils.openInTab("https://www.tool77.com/zh-CN/v/downloader?url=" + encodeURIComponent(window.location.href)); }, genrate: function() { if (!/www\.xiaohongshu\.com\/explore\//.test(window.location.href)) { return; } const noteContainer = document.querySelector("#noteContainer"); if (!noteContainer) { return; } if (noteContainer.querySelector("*[x-add='true']")) { return; } const mediaContainer = noteContainer.querySelector(".media-container"); if (!mediaContainer) { return; } const randomId = Math.floor(1e5 + Math.random() * 9e5); GM_addStyle(` .sc-download-` + randomId + `{ cursor:pointer; justify-content:center; align-items:center; width:40px; height:40px; z-index:99999; position:absolute; right:55px; top:10px; border-radius:50%; display: flex; border-radius:50%; } .sc-download-` + randomId + `::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(90deg,red, orange, yellow, green, cyan, blue, violet, red); background-size: 200% 200%; opacity: 0; transition: opacity .25s; -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; } .sc-download-` + randomId + `:hover::before { opacity: 1; animation: rainbowMove 3s linear infinite; } @keyframes rainbowMove { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } } `); const downloadElement = document.createElement("div"); downloadElement.setAttribute("x-add", "true"); downloadElement.classList.add("sc-download-" + randomId); downloadElement.appendChild(CommonUtils.genrateDownloadSvg("#FFF")); downloadElement.style.cursor = "pointer"; mediaContainer.appendChild(downloadElement); downloadElement.addEventListener("click", () => { this.downloadVideo(); }); }, start: function() { const isRun = /www\.xiaohongshu\.com/.test(window.location.host); if (isRun) { setInterval(() => { this.genrate(); }, 777); } } }; const Downloader = { cssInjected: false, isRun: function() { const hosts = [ /googlevideo\.com/, /tiktokcdn\.com/, /douyinvod\.com/, /fbcdn\.net/, /video\.twimg\.com/, /zjcdn\.com/, /snssdk\.com/, /tiktokv\.com/, /douyinstatic\.com/, /twimg\.com/, /xhscdn\.com/, /amemv\.com/, /tikwm\.com/, /tiktokcdn-eu\.com/, /tiktokcdn-us\.com/, /douyinpic\.com/, /douyinmusicpromotion\.com/, /cdninstagram\.com/ ]; const currentHost = window.location.host; return hosts.some((rule) => rule.test(currentHost)); }, getLanguage: function() { const lang = CommonUtils.getSupportedLang(); const langMap = { "en": { startDownload: "Start Download", cancelDownload: "Cancel Download", downloadProgress: "Download Progress:", downloadCompleted: "Download completed", downloadCompletedToast: "Download completed!", reDownload: "Download Again", downloadFailed: "Download failed", downloadFailedToast: "Download failed, please check console", downloadCanceledToast: "Download canceled", downloaderTip: "* If download fails, save manually: right click -> Save video as.
* If the file is too large (over 200MB), manual saving is recommended." }, "es": { startDownload: "Iniciar descarga", cancelDownload: "Cancelar descarga", downloadProgress: "Progreso de descarga:", downloadCompleted: "Descarga completada", downloadCompletedToast: "¡Descarga completada!", reDownload: "Descargar de nuevo", downloadFailed: "Error de descarga", downloadFailedToast: "La descarga falló, revise la consola", downloadCanceledToast: "Descarga cancelada", downloaderTip: "* Si la descarga falla, guarda manualmente: clic derecho -> Guardar video como.
* Si el archivo es demasiado grande (mas de 200MB), se recomienda guardar manualmente." }, "fr": { startDownload: "Demarrer le telechargement", cancelDownload: "Annuler le telechargement", downloadProgress: "Progression du telechargement :", downloadCompleted: "Telechargement termine", downloadCompletedToast: "Telechargement termine !", reDownload: "Telecharger a nouveau", downloadFailed: "Echec du telechargement", downloadFailedToast: "Le telechargement a echoue, verifiez la console", downloadCanceledToast: "Telechargement annule", downloaderTip: "* Si le telechargement echoue, enregistrez manuellement : clic droit -> Enregistrer la video sous.
* Si le fichier est trop volumineux (plus de 200MB), l'enregistrement manuel est recommande." }, "pt": { startDownload: "Iniciar download", cancelDownload: "Cancelar download", downloadProgress: "Progresso do download:", downloadCompleted: "Download concluido", downloadCompletedToast: "Download concluido!", reDownload: "Baixar novamente", downloadFailed: "Falha no download", downloadFailedToast: "Falha no download, verifique o console", downloadCanceledToast: "Download cancelado", downloaderTip: "* Se o download falhar, salve manualmente: clique direito -> Salvar video como.
* Se o arquivo for muito grande (acima de 200MB), recomenda-se salvar manualmente." }, "ru": { startDownload: "Начать загрузку", cancelDownload: "Отменить загрузку", downloadProgress: "Прогресс загрузки:", downloadCompleted: "Загрузка завершена", downloadCompletedToast: "Загрузка завершена!", reDownload: "Скачать снова", downloadFailed: "Ошибка загрузки", downloadFailedToast: "Сбой загрузки, проверьте консоль", downloadCanceledToast: "Загрузка отменена", downloaderTip: "* Если загрузка не удалась, сохраните вручную: правый клик -> Сохранить видео как.
* Если файл слишком большой (более 200MB), рекомендуется сохранять вручную." }, "ja": { startDownload: "ダウンロード開始", cancelDownload: "ダウンロードをキャンセル", downloadProgress: "ダウンロード進行状況:", downloadCompleted: "ダウンロード完了", downloadCompletedToast: "ダウンロードが完了しました!", reDownload: "再ダウンロード", downloadFailed: "ダウンロード失敗", downloadFailedToast: "ダウンロードに失敗しました。コンソールを確認してください", downloadCanceledToast: "ダウンロードをキャンセルしました", downloaderTip: "* ダウンロードに失敗した場合は手動保存: 右クリック -> 動画を名前を付けて保存。
* ファイルが大きすぎる場合(200MB超)、手動保存を推奨します。" }, "de": { startDownload: "Download starten", cancelDownload: "Download abbrechen", downloadProgress: "Download-Fortschritt:", downloadCompleted: "Download abgeschlossen", downloadCompletedToast: "Download abgeschlossen!", reDownload: "Erneut herunterladen", downloadFailed: "Download fehlgeschlagen", downloadFailedToast: "Download fehlgeschlagen, bitte Konsole pruefen", downloadCanceledToast: "Download abgebrochen", downloaderTip: "* Wenn der Download fehlschlaegt, manuell speichern: Rechtsklick -> Video speichern unter.
* Wenn die Datei zu gross ist (uber 200MB), wird manuelles Speichern empfohlen." }, "ko": { startDownload: "다운로드 시작", cancelDownload: "다운로드 취소", downloadProgress: "다운로드 진행률:", downloadCompleted: "다운로드 완료", downloadCompletedToast: "다운로드가 완료되었습니다!", reDownload: "다시 다운로드", downloadFailed: "다운로드 실패", downloadFailedToast: "다운로드에 실패했습니다. 콘솔을 확인하세요", downloadCanceledToast: "다운로드가 취소되었습니다", downloaderTip: "* 다운로드 실패 시 수동 저장: 마우스 오른쪽 클릭 -> 동영상을 다른 이름으로 저장.
* 파일이 너무 큰 경우(200MB 이상) 수동 저장을 권장합니다." }, "it": { startDownload: "Avvia download", cancelDownload: "Annulla download", downloadProgress: "Avanzamento download:", downloadCompleted: "Download completato", downloadCompletedToast: "Download completato!", reDownload: "Scarica di nuovo", downloadFailed: "Download non riuscito", downloadFailedToast: "Download non riuscito, controlla la console", downloadCanceledToast: "Download annullato", downloaderTip: "* Se il download fallisce, salva manualmente: clic destro -> Salva video con nome.
* Se il file e troppo grande (oltre 200MB), e consigliato il salvataggio manuale." }, "id": { startDownload: "Mulai unduh", cancelDownload: "Batalkan unduhan", downloadProgress: "Progres unduhan:", downloadCompleted: "Unduhan selesai", downloadCompletedToast: "Unduhan selesai!", reDownload: "Unduh lagi", downloadFailed: "Unduhan gagal", downloadFailedToast: "Unduhan gagal, periksa konsol", downloadCanceledToast: "Unduhan dibatalkan", downloaderTip: "* Jika unduhan gagal, simpan manual: klik kanan -> Simpan video sebagai.
* Jika file terlalu besar (lebih dari 200MB), disarankan simpan manual." }, "tr": { startDownload: "Indirmeyi baslat", cancelDownload: "Indirmeyi iptal et", downloadProgress: "Indirme ilerlemesi:", downloadCompleted: "Indirme tamamlandi", downloadCompletedToast: "Indirme tamamlandi!", reDownload: "Tekrar indir", downloadFailed: "Indirme basarisiz", downloadFailedToast: "Indirme basarisiz, lutfen konsolu kontrol edin", downloadCanceledToast: "Indirme iptal edildi", downloaderTip: "* Indirme basarisiz olursa manuel kaydedin: saga tik -> Videoyu farkli kaydet.
* Dosya cok buyukse (200MB ustu), manuel kaydetmeniz onerilir." }, "pl": { startDownload: "Rozpocznij pobieranie", cancelDownload: "Anuluj pobieranie", downloadProgress: "Postep pobierania:", downloadCompleted: "Pobieranie zakonczone", downloadCompletedToast: "Pobieranie zakonczone!", reDownload: "Pobierz ponownie", downloadFailed: "Pobieranie nieudane", downloadFailedToast: "Pobieranie nieudane, sprawdz konsole", downloadCanceledToast: "Pobieranie anulowane", downloaderTip: "* Jesli pobieranie sie nie powiedzie, zapisz recznie: prawy przycisk -> Zapisz wideo jako.
* Jesli plik jest zbyt duzy (powyej 200MB), zaleca sie zapis reczny." }, "uk": { startDownload: "Почати завантаження", cancelDownload: "Скасувати завантаження", downloadProgress: "Прогрес завантаження:", downloadCompleted: "Завантаження завершено", downloadCompletedToast: "Завантаження завершено!", reDownload: "Завантажити знову", downloadFailed: "Помилка завантаження", downloadFailedToast: "Не вдалося завантажити, перевірте консоль", downloadCanceledToast: "Завантаження скасовано", downloaderTip: "* Якщо завантаження не вдалося, збережіть вручну: правий клік -> Зберегти відео як.
* Якщо файл занадто великий (понад 200MB), рекомендовано зберігати вручну." }, "nl": { startDownload: "Download starten", cancelDownload: "Download annuleren", downloadProgress: "Downloadvoortgang:", downloadCompleted: "Download voltooid", downloadCompletedToast: "Download voltooid!", reDownload: "Opnieuw downloaden", downloadFailed: "Download mislukt", downloadFailedToast: "Download mislukt, controleer de console", downloadCanceledToast: "Download geannuleerd", downloaderTip: "* Als downloaden mislukt, handmatig opslaan: rechtermuisknop -> Video opslaan als.
* Als het bestand te groot is (meer dan 200MB), wordt handmatig opslaan aanbevolen." }, "vi": { startDownload: "Bat dau tai xuong", cancelDownload: "Huy tai xuong", downloadProgress: "Tien do tai xuong:", downloadCompleted: "Tai xuong hoan tat", downloadCompletedToast: "Tai xuong hoan tat!", reDownload: "Tai lai", downloadFailed: "Tai xuong that bai", downloadFailedToast: "Tai xuong that bai, vui long kiem tra console", downloadCanceledToast: "Da huy tai xuong", downloaderTip: "* Neu tai xuong that bai, hay luu thu cong: nhap chuot phai -> Luu video thanh.
* Neu tep qua lon (tren 200MB), khuyen nghi luu thu cong." }, "th": { startDownload: "เริ่มดาวน์โหลด", cancelDownload: "ยกเลิกการดาวน์โหลด", downloadProgress: "ความคืบหน้าการดาวน์โหลด:", downloadCompleted: "ดาวน์โหลดเสร็จสิ้น", downloadCompletedToast: "ดาวน์โหลดเสร็จสิ้น!", reDownload: "ดาวน์โหลดอีกครั้ง", downloadFailed: "ดาวน์โหลดล้มเหลว", downloadFailedToast: "ดาวน์โหลดล้มเหลว โปรดตรวจสอบคอนโซล", downloadCanceledToast: "ยกเลิกการดาวน์โหลดแล้ว", downloaderTip: "* หากดาวน์โหลดล้มเหลว ให้บันทึกด้วยตนเอง: คลิกขวา -> บันทึกวิดีโอเป็น.
* หากไฟล์มีขนาดใหญ่เกินไป (มากกว่า 200MB) แนะนำให้บันทึกด้วยตนเอง." }, "ar": { startDownload: "بدء التنزيل", cancelDownload: "إلغاء التنزيل", downloadProgress: "تقدم التنزيل:", downloadCompleted: "اكتمل التنزيل", downloadCompletedToast: "اكتمل التنزيل!", reDownload: "تنزيل مرة اخرى", downloadFailed: "فشل التنزيل", downloadFailedToast: "فشل التنزيل، يرجى التحقق من وحدة التحكم", downloadCanceledToast: "تم إلغاء التنزيل", downloaderTip: "* إذا فشل التنزيل، احفظ يدويًا: انقر بزر الماوس الأيمن -> حفظ الفيديو باسم.
* إذا كان الملف كبيرًا جدًا (أكثر من 200MB)، يوصى بالحفظ اليدوي." }, "fa": { startDownload: "شروع دانلود", cancelDownload: "لغو دانلود", downloadProgress: "پیشرفت دانلود:", downloadCompleted: "دانلود کامل شد", downloadCompletedToast: "دانلود کامل شد!", reDownload: "دانلود دوباره", downloadFailed: "دانلود ناموفق بود", downloadFailedToast: "دانلود ناموفق بود، لطفا کنسول را بررسی کنید", downloadCanceledToast: "دانلود لغو شد", downloaderTip: "* اگر دانلود ناموفق بود، به صورت دستی ذخیره کنید: راست کلیک -> ذخیره ویدیو با نام.
* اگر فایل خیلی بزرگ است (بیش از 200MB)، ذخیره دستی توصیه می شود." }, "hi": { startDownload: "डाउनलोड शुरू करें", cancelDownload: "डाउनलोड रद्द करें", downloadProgress: "डाउनलोड प्रगति:", downloadCompleted: "डाउनलोड पूरा हुआ", downloadCompletedToast: "डाउनलोड पूरा हुआ!", reDownload: "फिर से डाउनलोड करें", downloadFailed: "डाउनलोड असफल रहा", downloadFailedToast: "डाउनलोड असफल रहा, कृपया कंसोल जांचें", downloadCanceledToast: "डाउनलोड रद्द कर दिया गया", downloaderTip: "* यदि डाउनलोड असफल हो, मैन्युअली सेव करें: राइट क्लिक -> वीडियो को इस नाम से सेव करें.
* यदि फाइल बहुत बड़ी है (200MB से अधिक), मैन्युअल सेव करना सुझाया जाता है." }, "ms": { startDownload: "Mula muat turun", cancelDownload: "Batal muat turun", downloadProgress: "Kemajuan muat turun:", downloadCompleted: "Muat turun selesai", downloadCompletedToast: "Muat turun selesai!", reDownload: "Muat turun semula", downloadFailed: "Muat turun gagal", downloadFailedToast: "Muat turun gagal, sila semak konsol", downloadCanceledToast: "Muat turun dibatalkan", downloaderTip: "* Jika muat turun gagal, simpan secara manual: klik kanan -> Simpan video sebagai.
* Jika fail terlalu besar (lebih 200MB), simpan secara manual adalah disyorkan." }, "zh-CN": { startDownload: "开始下载", cancelDownload: "取消下载", downloadProgress: "下载进度:", downloadCompleted: "下载完成", downloadCompletedToast: "下载完成!", reDownload: "重新下载", downloadFailed: "下载失败", downloadFailedToast: "下载失败,请查看控制台", downloadCanceledToast: "下载已取消", downloaderTip: "* 如果下载失败,请手动保存:鼠标右键 -> 视频另存为。
* 如果文件太大(200MB)以上,推荐使用手动保存。" }, "zh-TW": { startDownload: "開始下載", cancelDownload: "取消下載", downloadProgress: "下載進度:", downloadCompleted: "下載完成", downloadCompletedToast: "下載完成!", reDownload: "重新下載", downloadFailed: "下載失敗", downloadFailedToast: "下載失敗,請查看控制台", downloadCanceledToast: "下載已取消", downloaderTip: "* 如果下載失敗,請手動儲存:滑鼠右鍵 -> 影片另存為。
* 如果檔案太大(200MB)以上,建議使用手動儲存。" } }; return langMap[lang] || langMap["en"]; }, generateCss: function() { if (this.cssInjected) { return; } GM_addStyle(` .downloader-gui { position: fixed; top: 20px; right: 20px; width: 250px; padding: 10px; background: rgba(0,0,0,0.8); color: #fff; font-family: Arial, sans-serif; border-radius: 8px; z-index: 99999; font-size: 15px; } .downloader-btn { width: 100%; padding: 6px 0; margin-bottom: 6px; color: #fff; border: none; border-radius: 4px; cursor: pointer; } .downloader-download-btn { background: #1a73e8; } .downloader-cancel-btn { background: #e53935; display: none; } .downloader-progress-container { display: none; } .downloader-progress-label { margin-bottom: 6px; } .downloader-progress-wrap { background: #555; height: 10px; border-radius: 4px; overflow: hidden; } .downloader-progress-bar { width: 0%; height: 100%; background: #0f0; } .downloader-progress-text { margin-top: 4px; font-size: 12px; } .downloader-tip{ font-size:11px; margin-top: 10px; } .downloader-toast { font-size: 15px; position: fixed; top: 20px; left: 50%; transform: translateX(-50%); padding: 10px 20px; background: rgba(0,0,0,0.8); color: #fff; border-radius: 6px; font-family: Arial, sans-serif; z-index: 100000; opacity: 0; transition: opacity 0.3s ease; } `); this.cssInjected = true; }, generateGui: function(language) { const mountNode = document.body || document.documentElement; if (!mountNode) { return null; } this.generateCss(); const gui = document.createElement("div"); gui.className = "downloader-gui"; gui.innerHTML = `
${language.downloadProgress}
0%
${language.downloaderTip}
`; mountNode.appendChild(gui); const downloadBtn = gui.querySelector('[data-role="download-btn"]'); const cancelBtn = gui.querySelector('[data-role="cancel-btn"]'); const progressContainer = gui.querySelector('[data-role="progress-container"]'); const progressBar = gui.querySelector('[data-role="progress-bar"]'); const progressText = gui.querySelector('[data-role="progress-text"]'); return { downloadBtn, cancelBtn, progressContainer, progressBar, progressText }; }, showToast: function(message) { const mountNode = document.body || document.documentElement; if (!mountNode) { return; } this.generateCss(); const toast = document.createElement("div"); toast.className = "downloader-toast"; toast.textContent = message; mountNode.appendChild(toast); requestAnimationFrame(() => toast.style.opacity = 1); setTimeout(() => { toast.style.opacity = 0; setTimeout(() => toast.remove(), 300); }, 2e3); }, setDownloadingState: function(doms) { const { downloadBtn, cancelBtn, progressContainer, progressBar, progressText } = doms; downloadBtn.style.display = "none"; cancelBtn.style.display = "block"; progressContainer.style.display = "block"; progressBar.style.width = "0%"; progressText.textContent = "0%"; }, setIdleState: function(doms, language) { const { downloadBtn, cancelBtn, progressContainer } = doms; progressContainer.style.display = "none"; cancelBtn.style.display = "none"; downloadBtn.style.display = "block"; downloadBtn.textContent = language.reDownload; }, currentRequest: null, addEvent: function(downloadData, doms, language) { const { downloadBtn, cancelBtn, progressContainer, progressBar, progressText } = doms; downloadBtn.addEventListener("click", () => { const onstart = () => { this.setDownloadingState(doms); }; const onprogress = (percent, loaded, total) => { progressBar.style.width = percent + "%"; progressText.textContent = `${percent}% | ${CommonUtils.formatBytes(loaded)}/${CommonUtils.formatBytes(total)}`; }; const onload = () => { this.currentRequest = null; progressBar.style.width = "100%"; progressText.textContent = language.downloadCompleted; this.showToast(language.downloadCompletedToast); this.setIdleState(doms, language); }; const onerror = (err) => { this.currentRequest = null; console.error("download error", err); progressText.textContent = language.downloadFailed; this.showToast(language.downloadFailedToast); this.setIdleState(doms, language); }; this.download(downloadData.url, downloadData.filename, onstart, onprogress, onload, onerror); }); cancelBtn.addEventListener("click", () => { if (this.currentRequest) { this.currentRequest.abort(); this.currentRequest = null; this.showToast(language.downloadCanceledToast); this.setIdleState(doms, language); } }); }, download: function(url, filename, onstart, onprogress, onload, onerror) { onstart(); this.currentRequest = GM_xmlhttpRequest({ method: "GET", url, responseType: "blob", onprogress: function(event) { if (event.lengthComputable) { const percent = (event.loaded / event.total * 100).toFixed(2); onprogress(percent, event.loaded, event.total); } }, onload: function(response) { if (response.status < 200 || response.status >= 300 || !response.response) { onerror(new Error(`Request failed with status ${response.status}`)); return; } const blob = response.response; const a = document.createElement("a"); const objectUrl = URL.createObjectURL(blob); a.href = objectUrl; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); setTimeout(() => URL.revokeObjectURL(objectUrl), 1e3); onload(); }, onerror: function(err) { onerror(err); }, onabort: function() { onerror(new Error("Request aborted")); }, ontimeout: function() { onerror(new Error("Request timeout")); } }); }, getFileExtension: function(url) { try { const videoSource = document.querySelector("video source"); const imageSource = document.querySelector("img"); let type = ""; if (typeof videoSource === "string" && videoSource) { url = videoSource; } else if (videoSource instanceof HTMLSourceElement && (videoSource.src || videoSource.type)) { url = videoSource.src || ""; type = videoSource.type || ""; } if (!(videoSource instanceof HTMLSourceElement) && !videoSource && imageSource) { url = String(url || ""); } const typeMap = { "audio/mpeg": "mp3", "audio/mp4": "mp4", "audio/ogg": "ogg", "audio/wav": "wav", "audio/webm": "webm", "audio/aac": "aac", "audio/flac": "flac", "audio/x-wav": "wav", "audio/x-ms-wma": "wma", "video/mp4": "mp4", "video/webm": "webm", "video/ogg": "ogv", "video/quicktime": "mov", "video/x-msvideo": "avi", "video/x-ms-wmv": "wmv", "video/mpeg": "mpeg", "video/3gpp": "3gp", "image/jpeg": "jpg", "image/jpg": "jpg", "image/png": "png", "image/gif": "gif", "image/webp": "webp", "image/svg+xml": "svg", "image/bmp": "bmp", "image/tiff": "tiff", "image/x-icon": "ico" }; const normalizedType = String(type).split(";")[0].trim().toLowerCase(); if (normalizedType && typeMap[normalizedType]) { return typeMap[normalizedType]; } if (!url) { return null; } const cleanUrl = String(url).split("?")[0].split("#")[0]; const fileName = cleanUrl.split("/").pop(); if (!fileName) { return null; } const match = fileName.match(/\.([a-zA-Z0-9]+)$/); return match ? match[1].toLowerCase() : null; } catch (error) { console.error("getFileExtension error", error); } return null; }, generateFilename: function(url) { let ext = ""; try { const parsedUrl = new URL(String(url)); ext = parsedUrl.searchParams.get("____ext_") || ""; } catch (err) { const match = String(url).match(/[?&]____ext_=([^&#]*)/); ext = match ? decodeURIComponent(match[1]) : ""; } ext = String(ext).trim().toLowerCase().replace(/^\./, ""); if (!ext || ext === "unknown") { ext = this.getFileExtension(url); } ext = String(ext || "").trim().toLowerCase().replace(/^\./, "").replace(/[^a-z0-9]/g, ""); if (!ext || ext === "unknown") { ext = "mp4"; } return `${Date.now()}.${ext}`; }, start: function() { if (!this.isRun()) { return; } const url = window.location.href; const downloadData = { filename: this.generateFilename(url), url }; const language = this.getLanguage(); const doms = this.generateGui(language); if (!doms) { return; } this.addEvent(downloadData, doms, language); } }; const TedDownloader = { createDownloadButtonClass: function() { return "sc-download-" + Math.floor(1e5 + Math.random() * 9e5); }, injectStyle: function(buttonClass) { GM_addStyle(` .${buttonClass}{ cursor:pointer; justify-content:center; align-items:center; width:40px; height:40px; z-index:999999; position:relative; border-radius:50%; display:flex; } .${buttonClass}::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(90deg,red, orange, yellow, green, cyan, blue, violet, red); background-size: 200% 200%; opacity: 0; transition: opacity .25s; -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; } .${buttonClass}:hover::before { opacity: 1; animation: rainbowMove 3s linear infinite; } @keyframes rainbowMove { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } } `); }, createDownloadButton: function(buttonClass) { const downloadElement = document.createElement("div"); downloadElement.setAttribute("x-add", "true"); downloadElement.classList.add(buttonClass); downloadElement.style.cursor = "pointer"; downloadElement.appendChild(CommonUtils.genrateDownloadSvg("#000")); downloadElement.addEventListener("click", () => { const url = "https://www.tool77.com/" + CommonUtils.getSupportedLang() + "/v/downloader?url=" + encodeURIComponent(window.location.href); CommonUtils.openInTab(url); }); return downloadElement; }, isTalkPage: function() { return /www\.ted\.com\/talks\//.test(window.location.href); }, injectDownloaderIfNeeded: function(buttonClass) { if (!this.isTalkPage()) { return; } if (document.querySelector("." + buttonClass)) { return; } const transcript = document.querySelector("#transcript-control"); const actionContainer = transcript?.parentNode?.querySelector(".items-center"); if (!actionContainer) { return; } actionContainer.appendChild(this.createDownloadButton(buttonClass)); }, setupPageObserver: function(buttonClass) { let rafId = null; const scheduleInject = () => { if (rafId !== null) { return; } rafId = requestAnimationFrame(() => { rafId = null; this.injectDownloaderIfNeeded(buttonClass); }); }; const observer = new MutationObserver(() => { scheduleInject(); }); observer.observe(document.documentElement, { childList: true, subtree: true }); const onLocationChange = () => { scheduleInject(); }; window.addEventListener("popstate", onLocationChange); window.addEventListener("hashchange", onLocationChange); const rawPushState = history.pushState; history.pushState = function(...args) { const ret = rawPushState.apply(this, args); onLocationChange(); return ret; }; const rawReplaceState = history.replaceState; history.replaceState = function(...args) { const ret = rawReplaceState.apply(this, args); onLocationChange(); return ret; }; scheduleInject(); }, generateHtml: function() { const buttonClass = this.createDownloadButtonClass(); this.injectStyle(buttonClass); this.setupPageObserver(buttonClass); }, start: function() { const isRun = /www\.ted\.com/.test(window.location.host); if (isRun) { this.generateHtml(); } } }; YouTubeDownloader.start(); TiktokDownloader.start(); ThreadsDownloader.start(); TwitterDownloader.start(); InstagramDownloader.start(); DouyinDownloader.start(); XiaoHongShuDownloader.start(); Downloader.start(); TedDownloader.start(); }());