在您安裝前,Greasy Fork希望您了解本腳本包含“可能不受歡迎的功能”,可能幫助腳本的作者獲利,而不能給你帶來任何收益。
作者從這份腳本獲得佣金, 例如透過重寫連結或提供優惠券代碼以加入推薦或附屬代碼
This script will provide enhancements to some websites. 🔥Twitter(X): Add time formatting display, HD picture display, picture and video downloading, etc. 🔥Youtube: Add video downloading, ad removal, etc. 🔥Tiktok: Provide HD watermark-free video downloading, etc. For more features, please check the description~
// ==UserScript== // @name Twitter(X)ᴾˡᵘˢ+++ ; Youtubeᴾˡᵘˢ+++,etc. // @name:hr Twitter(X)ᴾˡᵘˢ+++ ; Youtubeᴾˡᵘˢ+++,etc. // @description This script will provide enhancements to some websites. 🔥Twitter(X): Add time formatting display, HD picture display, picture and video downloading, etc. 🔥Youtube: Add video downloading, ad removal, etc. 🔥Tiktok: Provide HD watermark-free video downloading, etc. For more features, please check the description~ // @description:hr Ovaj skript pruža poboljšanja za neke web stranice: 🔥 Twitter (X) – dodaje prikaz formatiranja vremena, prikaz HD slika, preuzimanje slika i videozapisa itd. 🔥 YouTube – omogućuje preuzimanje videozapisa, uklanjanje oglasa itd. 🔥 TikTok – omogućuje preuzimanje HD videozapisa bez vodenog žiga itd. Za više značajki, provjerite opis! // @namespace PeterParker_X_Y_NameScope // @version 2.1.0 // @author PeterParker // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABhxJREFUeF7lm09oHUUcx3/7nm0aWou2CtL2kFLbREXFRPBU+tJb8Gb1Yg8VhIhHb6U86HvwKKWCR8WAx3qRipfYW7rBk2Iq2EvTKkUspRhbJTRpm/p25TdvZ3d2dmb2N7vzNnnJQMhLdnZ2vp/5/dvdeR5s8eZtcf1QHYDmL40EdhB99o4BhPPpRaj50HnDr2ph+guAiQ7PRmIEAFR5YZv17Ey0qGfY9nMPIBEdCz56/xab19F70e/ob/zfD3sOxnM+d/i4Yf79geEOgCSciz5zcw74Z8rqIBD2s7f3O9vcgigPQCHcVrQOzLkXj4PeKtyAKAegudAC8JiP4yq7Ei4DyQVRIkYUB9C8egUAmJ+j+Ms/fkWx8FJ9pt76UOMW4ENnfLLI4PYAeiaP4lnDVT/z21yRaxc6x2wN3qRtCrUDIJj8eojnxFy6BB3ABhHvGgINgGT2Vfl8no8YYgIA0NyBCOBqKE7mweVm3twqO75rqqO/Vmc8V19uBxCi/Xr6vU4lFktoCZqWmx3MACS/x4tspNXnos2uELZN9xJ6AArxVac8FFifeBW6C9eMLpVjBcZ4YAXAZvV3fHk+nvSTmYtKEShu2/TJuN+jj07Hn/EYH+PJzNewNnPRCMFsBfpCSQ2g5OqLk8dZozDVKqJA7IsNj4sAxGN4fOXNt8sA0FpBJQB0k9/582wsygRAPqYike8GaivIAlCsvm3wM62sOHkRgGwl3D2ChWvQXfg1Nw7guMaUyC6crQ1IAGwLHwoAqpvYFBQ5cQCHyqRFBYB00VMk94srqwtg26dPwrbp92N9opvIwRGtIC8I4kDme4ToUlJxlAagMX+b9CevLAJAE5YbRn9dACxqHSQAkhv0HQDFhOUgJ1uHLovIYxMCYcYNJABZ88cz8GEH9bmenL4oAGQ3sU2B/Bp9A2DjAvLkdVUcN39VnWBKjyagNBdIZ4PEAqRbXvFCNgBcBMB0FZlfBfK5lgSQPOCUKVPTIDV4mdIkdQyVJWwKAEUDIDkNMnLJHaLgAnoLoFaC1OBlchPqGCoLyK8E+VkFAFAygYsKsGgAJGYATiCuCAULSJ7zq+hS4gBl8iYTVxVRlArQzvwLugDFDVAcb7obGBRZn3gt7icKLBMA6eZfAgDFDSiFj+s+9OhvjAHpNz66Sdo8FXItVDee3eprLYAGwKYoqgKA/eoXqARlIRvJFexXH3ecJO8L5Juh+I2vafUoGaGK1cdrrAsAvDAVQv1IgqJ+mI6lezPp272hP88eQPo9gWQBtDjAp8PjAYpEcTVBoCicLtvck4MIIjgIafiQ4dWYcjgTADyhqX4mgIcae3ubnBrP3YJj/HP025XIouO0b/Q2WPl/HwT/nmpvUTSy8ZFYD4AyDrRG5+Dskeo2QhQFgechjNaiasdZ9jUZc4Hwm7FGUOttd1lYHRmZXR4/JU+gse8u4M8gNP/OC4A/cnt5x+35d5/5iW3CrAXge+9d92MAYS3Z9qIS6e3eA7D72UHQD7D8D4TL941z9QJvMgaAPbuXxlpesqsze/LQMHjP79sUALh4FJPKAkYIAwQgXLoD8PihOgeA166fuB5vvc28GAkujaZ2g8SjbAYAHvi1dxZT2+kyADAgKuPBJgAgmj5fWOXbYaUrDBKA279nzF8lPhMD+Fk6K/AOHBqIIBgqANROLCoXW/nP4NvRKxD26gKxDTKAUAp+RhfQBUJbAGJJOh+Vp1iqqhqW13LDcpuX3zamp7IAVvworIAeBDFnalyAC21H5aexFrdRIvVFGByUtix//BBYGlQ0lRVk06DG/FnAwEJoaBi6q6vw5901+O6vV+CTpY9LSCp/6uzYZ/D68B+w/8DTvcHKANCmwGiej4KnYHnpX1hdWYOVB2vwRXgKPg8+KK+ixAgXhj6Fqf++h527trNRRl7ary2CVG6QsgAEQJ0L1tGg2VBBHcNNv94dHnXubN5Cy98qmzdLBoE5CP92WN4Zro77AF7b9vsB8sXLA+AjVgfCiXA+bXcA+g/CqfD+ARBtrJxVRL5a3sxNPufeAkxXY7tQ+Ndm4zUQvj5bSwJURV+frRaAq/DncJwtD+B/6XGfbp4XQ5oAAAAASUVORK5CYII= // @include https://x.com/* // @include https://twitter.com/* // @include https://mobile.x.com/* // @include https://www.youtube.com/** // @include https://music.youtube.com/watch** // @include https://www.tiktok.com/@* // @include https://cobalt.tools/** // @exclude *://accounts.youtube.com/* // @exclude *://www.youtube.com/live_chat_replay* // @exclude *://www.youtube.com/persist_identity* // @exclude *://x.com/i/flow/* // @connect tikdownloader.io // @license MIT // @run-at document-idle // @antifeature referral-link // @noframes // @grant GM_registerMenuCommand // @grant GM_openInTab // @grant GM.openInTab // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_setClipboard // ==/UserScript== (function () { 'use strict'; /*! * Copyright (c) 2024 - 2025, PeterParker. 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 ScriptConst = { "lang": (navigator.language || navigator.userLanguage).slice(0, 2).toLowerCase(), "isDev": false, "isDebug": false, "currentHost": window.location.host, "currentUrl": window.location.href }; const PlatformConst = { "aliexpress": "aliexpress", "amazon": "amazon", "shopee": "shopee", "lazada": "lazada", "ebay": "ebay", "bestbuy": "bestbuy", "banggood": "banggood", "wish": "wish", "airbaltic": "airbaltic", "edureka": "edureka", "ranavat": "ranavat", "alibaba": "alibaba", "ticketmaster": "ticketmaster", "wilson": "wilson", "wilsonsleather": "wilsonsleather", "pictarine": "pictarine", "suiteness": "suiteness", "trip": "trip", "treatwell": "treatwell", "samsung": "samsung", "x": "x", "youtube": "youtube", "tiktok": "tiktok", "cobalt": "cobalt", "temu": "temu", "walmart": "walmart", "wildberries": "wildberries", "zalando": "zalando", "noon": "noon", "daraz": "daraz", "ozon": "ozon", "allegro": "allegro", "rakuten": "rakuten" }; var __async$3 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const Tools = { decryptStr: function(str) { if (!str) return str; let result = atob(str); return result.split("").reverse().join(""); }, encryptStr: function(str) { if (!str) return str; let result = str.split("").reverse().join(""); return btoa(result); }, getEcommercePlatform: function() { let platform = null; const currentHost = window.location.host; if (/amazon\./.test(currentHost)) { platform = PlatformConst.amazon; } else if (/ebay\./.test(currentHost)) { platform = PlatformConst.ebay; } else if (/lazada\./.test(currentHost)) { platform = PlatformConst.lazada; } else if (/aliexpress./.test(currentHost)) { platform = PlatformConst.aliexpress; } else if (/bestbuy\./.test(currentHost)) { platform = PlatformConst.bestbuy; } else if (/banggood\./.test(currentHost)) { platform = PlatformConst.banggood; } else if (/wish\./.test(currentHost)) { platform = PlatformConst.wish; } else if (/airbaltic\./.test(currentHost)) { platform = PlatformConst.airbaltic; } else if (/edureka\./.test(currentHost)) { platform = PlatformConst.edureka; } else if (/ranavat\./.test(currentHost)) { platform = PlatformConst.ranavat; } else if (/alibaba\./.test(currentHost)) { platform = PlatformConst.alibaba; } else if (/ticketmaster\./.test(currentHost)) { platform = PlatformConst.ticketmaster; } else if (/wilson\./.test(currentHost)) { platform = PlatformConst.wilson; } else if (/wilsonsleather\./.test(currentHost)) { platform = PlatformConst.wilsonsleather; } else if (/pictarine\./.test(currentHost)) { platform = PlatformConst.pictarine; } else if (/suiteness\./.test(currentHost)) { platform = PlatformConst.suiteness; } else if (/trip\./.test(currentHost)) { platform = PlatformConst.trip; } else if (/treatwell\./.test(currentHost)) { platform = PlatformConst.treatwell; } else if (/samsung\./.test(currentHost)) { platform = PlatformConst.samsung; } else if (/temu\./.test(currentHost)) { platform = PlatformConst.temu; } else if (/walmart\./.test(currentHost)) { platform = PlatformConst.walmart; } else if (/shopee\./.test(currentHost)) { platform = PlatformConst.shopee; } else if (/wildberries\./.test(currentHost)) { platform = PlatformConst.wildberries; } else if (/zalando\./.test(currentHost)) { platform = PlatformConst.zalando; } else if (/noon\./.test(currentHost)) { platform = PlatformConst.noon; } else if (/daraz\./.test(currentHost)) { platform = PlatformConst.daraz; } else if (/ozon\./.test(currentHost)) { platform = PlatformConst.ozon; } else if (/allegro\./.test(currentHost)) { platform = PlatformConst.allegro; } else if (/rakuten\./.test(currentHost)) { platform = PlatformConst.rakuten; } return platform; }, getOtherPlatform: function() { let platform = null; const currentHost = window.location.host; if (/twitter|x\.com$/.test(currentHost)) { platform = PlatformConst.x; } else if (/youtube\.com$/.test(currentHost)) { platform = PlatformConst.youtube; } else if (/www\.tiktok\.com/.test(currentHost)) { platform = PlatformConst.tiktok; } else if (/cobalt\.tools/.test(currentHost)) { platform = PlatformConst.cobalt; } return platform; }, getAllMatchPlatform: function() { var _a; return (_a = this.getEcommercePlatform()) != null ? _a : this.getOtherPlatform(); }, removeAnchorsByNode: function(node) { const tagName = node.tagName; if (!tagName) return; const exist = ["A", "IMG", "DIV", "SPAN", "LABEL", "TABLE", "TR", "TD", "CANVAS"].some((name) => name === tagName); if (exist) { node.removeAttribute("data-spm-anchor-id"); for (let i = 0; i < node.childNodes.length; i++) { this.removeAnchorsByNode(node.childNodes[i]); } } }, removeAnchorsBySeletor: function() { document.querySelectorAll("*[data-re-mark-tag='aliexpress']").forEach((element) => { this.removeAnchorsByNode(element); }); }, openInTab: function(url, options = { "active": true, "insert": true, "setParent": true }) { if (typeof GM_openInTab === "function") { GM_openInTab(url, options); } else { GM.openInTab(url, options); } }, request: function(method, url, param, headers = { "Content-Type": "application/json;charset=UTF-8" }, timeout = 20 * 1e3) { if (!url) { return Promise.reject({ "code": "exception", "result": null }); } return new Promise((resolve, reject) => { const config = { method: method.toUpperCase(), url, timeout, onload: function(response) { if (response.status >= 200 && response.status < 300) { resolve({ "code": "success", "result": response.responseText }); } else { reject({ "code": "error", "result": response.statusText }); } }, ontimeout: function(error) { reject({ "code": "error", "result": error }); }, onerror: function(error) { reject({ "code": "error", "result": error }); } }; if (config.method === "POST") { config.headers = headers != null ? headers : { "Content-Type": "application/json" }; if (JSON.stringify(config.headers).indexOf("application/json") != -1) { config.data = JSON.stringify(param); } else { config.data = param; } } else if (config.method === "GET") { config.headers = headers != null ? headers : { "Content-Type": "application/json" }; config.data = param; } GM_xmlhttpRequest(config); }); }, crossRequest: function(method = "GET", url, param = {}, headers = { "Content-Type": "application/json;charset=UTF-8" }, timeout = 20 * 1e3) { if (!url) { return Promise.reject({ "code": "exception", "result": null }); } const config = { method: method.toUpperCase(), headers }; const controller = new AbortController(); const signal = controller.signal; config.signal = signal; if (config.method === "POST") { config.headers = headers != null ? headers : { "Content-Type": "application/json" }; config.body = JSON.stringify(param); } const timeoutId = setTimeout(() => controller.abort(), timeout); return fetch(url, config).then((response) => response.ok ? response.text() : Promise.reject(response.statusText)).then((result) => { clearTimeout(timeoutId); return { "code": "success", "result": result }; }).catch((error) => { clearTimeout(timeoutId); if (error.name === "AbortError") { return { "code": "error", "result": "Request timeout" }; } return { "code": "error", "result": error }; }); }, getParamterBySuffix: function(url = window.location.href, suffix = "html") { if (url.indexOf("?") != -1) { url = url.split("?")[0]; } if (url.indexOf("#") != -1) { url = url.split("#")[0]; } let regex = new RegExp("\\/([^\\/]*?)\\." + suffix); if (/lazada/.test(url)) { regex = new RegExp("-i(\\d+)(?:-s(\\d+))?\\.html"); } else if (/www\.ebay/.test(url)) { regex = new RegExp("\\/itm\\/(\\d+)"); } const match = url.match(regex); return match ? match[1] : null; }, getParamterBySearch: function(paramsString = window.location.href, tag) { if (paramsString.indexOf("?") != -1) { paramsString = paramsString.split("?")[1]; } const params = new URLSearchParams(paramsString); return params.get(tag); }, waitForElementByInterval: function(selector, target = document.body, allowEmpty = true, delay = 10, maxDelay = 10 * 1e3) { return new Promise((resolve, reject) => { let totalDelay = 0; let element = target.querySelector(selector); let result = allowEmpty ? !!element : !!element && !!element.innerHTML; if (result) { resolve(element); } const elementInterval = setInterval(() => { if (totalDelay >= maxDelay) { clearInterval(elementInterval); resolve(null); } element = target.querySelector(selector); result = allowEmpty ? !!element : !!element && !!element.innerHTML; if (result) { clearInterval(elementInterval); resolve(element); } else { totalDelay += delay; } }, delay); }); }, randomNumber: function() { return Math.ceil(Math.random() * 1e8); }, elementInContainer: function(container, element) { return container.contains(element); }, mustGetElement: function(handler) { return __async$3(this, null, function* () { const getElements = (handler2) => __async$3(this, null, function* () { const promiseArray = []; const handlers = handler2.split("@"); for (let i = 0; i < handlers.length; i++) { const eleName = handlers[i]; if (!eleName) { continue; } if (eleName == "body") { promiseArray.push( new Promise((resolve, reject) => { resolve(document.body); }) ); } else if (eleName == "html") { promiseArray.push( new Promise((resolve, reject) => { resolve(document.html); }) ); } else { promiseArray.push(this.waitForElementByInterval(eleName, document.body, true, 10, 1500)); } } let element2 = yield Promise.race(promiseArray); return element2; }); let element = yield getElements(handler); return new Promise((resolve, reject) => { if (element) { resolve(element); return; } const waitInterval = setInterval(() => { element = getElements(handler); if (element) { clearInterval(waitInterval); resolve(element); return; } }, 2e3); }); }); }, loopTask: function(callback, delay = 1500) { callback(); setInterval(() => { callback(); }, delay); }, distinguishRemoveAndTry: function(distinguish, callback) { const distinguishElements = distinguish.map((name) => document.querySelector("*[name='" + name + "']")); const validateRs = distinguishElements.some((ele) => ele === null || ele === void 0); if (validateRs) { distinguishElements.reverse().forEach((element) => { if (element) { element.remove(); } }); callback(); } }, getDomain: function(url) { try { const hostname = new URL(url).hostname; const parts = hostname.split("."); if (parts.length > 2) { return `${parts[parts.length - 2]}.${parts[parts.length - 1]}`; } return hostname; } catch (error) { console.error("Invalid URL:", error); return null; } }, getCommonMarketplace: function(url = window.location.href) { try { const domainParts = new URL(url).hostname.split("."); const countryCode = domainParts[domainParts.length - 1]; return countryCode; } catch (error) { console.log(error); } return null; } }; const Toast = { show: function(params) { let time = params.time; let background = params.background; let color = params.color; let position = params.position; let defaultMarginValue = 50; if (time == void 0 || time == "") { time = 1500; } if (position == void 0 || position == "") { position = "center-bottom"; } const style = document.createElement("style"); style.textContent = `@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-moz-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-o-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-ms-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-moz-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-o-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-ms-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.toast-style-kk998y{position:fixed;background:rgba(0,0,0,0.7);color:#fff;font-size:14px;line-height:1;padding:10px;border-radius:3px;left:50%;transform:translateX(-50%);-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-o-transform:translateX(-50%);-ms-transform:translateX(-50%);z-index:999999999999999999999999999;white-space:nowrap}.fadeOut{animation:fadeOut .5s}.fadeIn{animation:fadeIn .5s}`; const el = document.createElement("div"); if (background != void 0 && background != "") { el.style.backgroundColor = background; } if (color != void 0 && color != "") { el.style.color = color; } el.setAttribute("class", "toast-style-kk998y"); el.innerText = params.message; el.style.zIndex = 999999999; if (position === "center-bottom") { el.style.bottom = defaultMarginValue + "px"; } else { el.style.top = defaultMarginValue + "px"; } document.body.appendChild(el); document.head.appendChild(style); el.classList.add("fadeIn"); setTimeout(function() { el.classList.remove("fadeIn"); el.classList.add("fadeOut"); el.addEventListener("animationend", function() { document.body.removeChild(el); document.head.removeChild(style); }); el.addEventListener("webkitAnimationEnd", function() { document.body.removeChild(el); document.head.removeChild(style); }); }, time); } }; var _a; const language = { "zh": { "dateFormat": { "week": ["日", "一", "二", "三", "四", "五", "六"] }, "download": { "download": "下载", "completed": "下载完成", "tip": "点击下载视频", "preparing": "正在准备下载(如果失败,请手动操作)" }, "menuCommand": { "settings": "设置", "titleDateFormat": "时间格式设置:", "buttonClose": "关闭" } }, "en": { "dateFormat": { "week": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] }, "download": { "download": "Download", "completed": "Download Completed", "tip": "Click to download video", "preparing": "Preparing to download (if failed, please do it manually)" }, "menuCommand": { "settings": "Settings", "titleDateFormat": "Time format settings:", "buttonClose": "Close" } }, "ja": { "dateFormat": { "week": ["日", "月", "火", "水", "木", "金", "土"] }, "download": { "download": "ダウンロード", "completed": "ダウンロード完了", "tip": "クリックしてビデオをダウンロード", "preparing": "ダウンロードの準備中(失敗する場合は手動で行ってください)" }, "menuCommand": { "settings": "設定", "titleDateFormat": "時刻形式の設定:", "buttonClose": "閉鎖" } }, "fr": { "dateFormat": { "week": ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"] }, "download": { "download": "télécharger", "completed": "éléchargement terminé", "tip": "Cliquez pour télécharger la vidéo", "preparing": "Préparation du téléchargement (en cas d'échec, veuillez le faire manuellement)" }, "menuCommand": { "settings": "installation", "titleDateFormat": "Paramètres du format de l'heure :", "buttonClose": "fermeture" } }, "de": { "dateFormat": { "week": ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"] }, "download": { "download": "herunterladen", "completed": "Download abgeschlossen", "tip": "Klicken Sie hier, um das Video herunterzuladen", "preparing": "Vorbereitung für den Download (falls der Download fehlschlägt, führen Sie ihn bitte manuell durch)" }, "menuCommand": { "settings": "aufstellen", "titleDateFormat": "Einstellungen für das Zeitformat:", "buttonClose": "Schließung" } }, "it": { "dateFormat": { "week": ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"] }, "download": { "download": "scaricamento", "completed": "Download completato", "tip": "Fare clic per scaricare il video", "preparing": "Preparazione per il download (se fallisce, eseguilo manualmente)" }, "menuCommand": { "settings": "impostare", "titleDateFormat": "Impostazioni del formato dell'ora:", "buttonClose": "chiusura" } }, "ko": { "dateFormat": { "week": ["일", "월", "화", "수", "목", "금", "토"] }, "download": { "download": "다운로드", "completed": "다운로드 완료", "tip": "비디오를 다운로드하려면 클릭하세요", "preparing": "다운로드 준비 중 (실패할 경우 수동으로 진행해주세요)" }, "menuCommand": { "settings": "설정", "titleDateFormat": "시간 형식 설정:", "buttonClose": "폐쇄" } }, "ru": { "dateFormat": { "week": ["ВС", "ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ"] }, "download": { "download": "скачать", "completed": "Загрузка завершена", "tip": "Нажмите, чтобы скачать видео", "preparing": "Подготовка к загрузке (если не получается, сделайте это вручную)" }, "menuCommand": { "settings": "настраивать", "titleDateFormat": "Настройки формата времени:", "buttonClose": "закрытие" } }, "pt": { "dateFormat": { "week": ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"] }, "download": { "download": "descargar", "completed": "Descarga completa", "tip": "Clique para baixar o vídeo", "preparing": "Preparação para download (se falhar, faça-o manualmente)" }, "menuCommand": { "settings": "configuración", "titleDateFormat": "Configuración de formato de hora:", "buttonClose": "cierre" } }, "es": { "dateFormat": { "week": ["DOM", "LUN", "MAR", "MIER", "JUE", "VIE", "SÁB"] }, "download": { "download": "descargar", "completed": "Descarga completa", "tip": "Haga clic para descargar el vídeo", "preparing": "Preparándose para la descarga (si falla, hágalo manualmente)" }, "menuCommand": { "settings": "configuración", "titleDateFormat": "Configuración de formato de hora:", "buttonClose": "cierre" } }, "th": { "dateFormat": { "week": ["วันอาทิตย์", "วันจันทร์", "วันอังคาร", "วันพุธ", " วันพฤหัสบดี", "วันศุกร์ ", "วันเสาร์ "] }, "download": { "download": "ดาวน์โหลด", "completed": "ดาวน์โหลดเสร็จสมบูรณ์", "tip": "คลิกเพื่อดาวน์โหลดวิดีโอ", "preparing": "กำลังเตรียมการดาวน์โหลด (หากล้มเหลว กรุณาดำเนินการด้วยตนเอง)" }, "menuCommand": { "settings": "ตั้งค่า", "titleDateFormat": "การตั้งค่ารูปแบบเวลา:", "buttonClose": "ปิด" } }, "tr": { "dateFormat": { "week": ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"] }, "download": { "download": "indirmek", "completed": "İndirme tamamlandı", "tip": "Videoyu indirmek için tıklayın", "preparing": "İndirmeye hazırlanıyor (başarısız olursa lütfen manuel olarak yapın)" }, "menuCommand": { "settings": "kurmak", "titleDateFormat": "Saat formatı ayarları:", "buttonClose": "kapatma" } }, "nl": { "dateFormat": { "week": ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"] }, "download": { "download": "downloaden", "completed": "Downloaden voltooid", "tip": "Klik om video te downloaden", "preparing": "Voorbereiden voor downloaden (als dit mislukt, doe dit dan handmatig)" }, "menuCommand": { "settings": "opgezet", "titleDateFormat": "Instellingen tijdformaat:", "buttonClose": "sluiting" } } }; const Commonlanguage = (_a = language[ScriptConst["lang"]]) != null ? _a : language["en"]; var __async$2 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const FMT = 7; let fmt = GM_getValue("fmt", FMT); const XSettingsDialog = { number: Math.ceil(Math.random() * 1e8), formats: [ { "format": "Do nothing", "example": "N/A" }, { "format": "dd.MM.yy HH:mm", "example": "22.10.24 03:12" }, { "format": "dd.MM.yy HH:mm:ss", "example": "22.10.24 03:12:56" }, { "format": "dd.MM.yy(W) HH:mm", "example": "22.10.24(Mon) 03:12" }, { "format": "dd.MM.yy(W) HH:mm:ss", "example": "22.10.24(Mon) 03:12:56" }, { "format": "yy/MM/dd HH:mm", "example": "24/10/22 03:12" }, { "format": "yy/MM/dd HH:mm:ss", "example": "24/10/22 03:12:56" }, { "format": "yy/MM/dd(W) HH:mm", "example": "24/10/22(Mon) 03:12" }, { "format": "yy/MM/dd(W) HH:mm:ss [ye/mo/da(we) ho:mi:se]", "example": "24/10/22(Mon) 03:12:56 [ye/mo/da(we) ho:mi:se]" }, { "format": "yy-MM/dd HH:mm", "example": "24-10/22 03:12" }, { "format": "yy-MM/dd HH:mm'ss", "example": "24-10/22 03:12'56" }, { "format": "yy-MM/dd(W) HH:mm", "example": "24-10/22(Mon) 03:12" }, { "format": "yy-MM/dd(W) HH:mm'ss", "example": "24-10/22(Mon) 03:12'56" }, { "format": "MM/dd/yy HH:mm", "example": "10/22/24 03:12" }, { "format": "MM/dd/yy HH:mm:ss", "example": "10/22/24 03:12:56" }, { "format": "W, MM/dd/yy HH:mm", "example": "Mon, 10/22/24 03:12" }, { "format": "W, MM/dd/yy HH:mm:ss", "example": "Mon, 10/22/24 03:12:56" }, { "format": "M59-MM-dd HH:mm", "example": "M59-10-22 03:12" }, { "format": "M59-MM-dd HH:mm:ss", "example": "M59-10-22 03:12:56" }, { "format": "M59-MM-dd(W) HH:mm", "example": "M59-10-22(Mon) 03:12" }, { "format": "M59-MM-dd(W) HH:mm:ss", "example": "M59-10-22(Mon) 03:12:56" } ], make: function() { let dialog = document.createElement("div"); dialog.className = "dialog_u_" + this.number; dialog.style.all = "initial"; dialog.style.backgroundColor = "rgb(255, 255, 255)"; dialog.style.border = "1px solid #ccc"; dialog.style.borderRadius = "2px"; dialog.style.display = "none"; dialog.style.fontFamily = "monospace"; dialog.style.fontSize = "12px"; dialog.style.width = "480px"; dialog.style.paddingLeft = "5px"; dialog.style.paddingRight = "5px"; dialog.style.paddingTop = "5px"; dialog.style.paddingBottom = "5px"; dialog.style.position = "fixed"; dialog.style.right = "8px"; dialog.style.top = "8px"; dialog.style.zIndex = "2147483647"; dialog.style.overflow = "auto"; let formatsHtml = `<table style="width:100%;border: 1px solid #c0bfbf;border-collapse: collapse;">`; for (var i = 1; i <= this.formats.length; i++) { if (i % 2 != 0) { formatsHtml += `<tr style="width:100%;border: 1px solid #c0bfbf;">`; } formatsHtml += `<td width="50" style="border: 1px solid #c0bfbf;padding: 5px 0px;" title="` + this.formats[i - 1].example + `"><input type="radio" name="fmt" value="` + (i - 1) + `" class="top_r" />` + ("【" + i + "】" + this.formats[i - 1].format) + `</td>`; if (i % 2 == 0) { formatsHtml += `</tr>`; } } formatsHtml += `</table>`; let html = ` <div style="font-size:15px;font-weight:bold;margin-bottom:5px;">` + Commonlanguage.menuCommand.titleDateFormat + `</div> <div>` + formatsHtml + `</div> <div style="margin-top:15px;text-align:center;"> <button name="closex">` + Commonlanguage.menuCommand.buttonClose + `</button> </div> `; dialog.innerHTML = html; return dialog; }, addEvent: function(dialog) { dialog.querySelector("button[name='closex']").addEventListener("click", function(event) { for (let e of dialog.querySelectorAll('input[name="fmt"]')) { if (e.checked) { fmt = e.value; break; } } GM_setValue("fmt", fmt); dialog.style.display = "none"; }, false); }, init: function() { let dialog = this.make(); this.addEvent(dialog); document.body.appendChild(dialog); GM_registerMenuCommand(Commonlanguage.menuCommand.settings, function() { if (dialog.style.display == "none") { dialog.querySelector('input[name="fmt"][value="' + fmt + '"]').checked = true; dialog.style.display = "block"; } }); } }; const XDateFormat = { df: function(date, f) { var _a; const WEEK = Commonlanguage.dateFormat.week; const YE = date.getFullYear().toString().slice(-2); const YM = date.getFullYear() - 1911; const MO = ("0" + (date.getMonth() + 1)).slice(-2); const DA = ("0" + date.getDate()).slice(-2); const WE = WEEK[date.getDay()]; const HO = ("0" + date.getHours()).slice(-2); const MI = ("0" + date.getMinutes()).slice(-2); const SE = ("0" + date.getSeconds()).slice(-2); const F = [ DA + "." + MO + "." + YE + " " + HO + ":" + MI, DA + "." + MO + "." + YE + " " + HO + ":" + MI + ":" + SE, DA + "." + MO + "." + YE + "(" + WE + ") " + HO + ":" + MI, DA + "." + MO + "." + YE + "(" + WE + ") " + HO + ":" + MI + ":" + SE, YE + "/" + MO + "/" + DA + " " + HO + ":" + MI, YE + "/" + MO + "/" + DA + " " + HO + ":" + MI + ":" + SE, YE + "/" + MO + "/" + DA + "(" + WE + ") " + HO + ":" + MI, YE + "/" + MO + "/" + DA + "(" + WE + ") " + HO + ":" + MI + ":" + SE, YE + "-" + MO + "/" + DA + " " + HO + ":" + MI, YE + "-" + MO + "/" + DA + " " + HO + ":" + MI + "'" + SE, YE + "-" + MO + "/" + DA + "(" + WE + ") " + HO + ":" + MI, YE + "-" + MO + "/" + DA + "(" + WE + ") " + HO + ":" + MI + "'" + SE, MO + "/" + DA + "/" + YE + " " + HO + ":" + MI, MO + "/" + DA + "/" + YE + " " + HO + ":" + MI + ":" + SE, WE + ", " + MO + "/" + DA + "/" + YE + " " + HO + ":" + MI, WE + ", " + MO + "/" + DA + "/" + YE + " " + HO + ":" + MI + ":" + SE, "M" + YM + "-" + MO + "-" + DA + " " + HO + ":" + MI, "M" + YM + "-" + MO + "-" + DA + " " + HO + ":" + MI + ":" + SE, "M" + YM + "-" + MO + "-" + DA + "(" + WE + ") " + HO + ":" + MI, "M" + YM + "-" + MO + "-" + DA + "(" + WE + ") " + HO + ":" + MI + ":" + SE ]; return (_a = F[f]) != null ? _a : F[0]; }, repldatetime: function() { const MYNAME = "peter_parker_x1190"; const SEL = 'main div[data-testid="primaryColumn"] section article time[datetime*=":"]'; const SEL_2 = 'div[aria-labelledby="modal-header"] div[data-testid^="User-Name"] time[datetime]'; const SEL_3 = 'div[aria-labelledby="modal-header"] div[aria-label] time[datetime]'; const SEL_4 = 'main section[aria-labelledby="detail-header"] article div[data-testid^="User-Name"] time[datetime]'; const SEL_5 = 'main section div[data-testid="conversation"] div[aria-label] time[datetime]'; document.querySelectorAll(SEL + ", " + SEL_2 + ", " + SEL_3 + ", " + SEL_4 + ", " + SEL_5).forEach((e) => { if (fmt != 0) { const SEL_ADD = "span.us-" + MYNAME; let d = e.getAttribute("datetime"); let df = this.df(new Date(d), fmt - 1); let pe = e.parentNode; let old = pe.querySelectorAll(SEL_ADD); if (!old.length) { let span = document.createElement("span"); span.className = "us-" + MYNAME; span.setAttribute("datetime", d); span.setAttribute("local-datetime", df); span.textContent = df; span.style = e.style; e.style.setProperty("display", "none"); pe.appendChild(span); } else if (old[0].getAttribute("local-datetime") != df) { old[0].setAttribute("local-datetime", df); old[0].textContent = df; old[0].style = e.style; } } }); } }; const XOrigimg = () => { const SEL_D = 'div[style*="background-image:"]'; const SEL_I = "img"; let elms = document.querySelectorAll(SEL_D + ", " + SEL_I); for (let e of elms) { let regex = /^(.+pbs\.twimg\.com\/[^?]+\?format=\w+)(&|&)(name=)(\w+)([")]*)$/; if (/div/i.test(e.tagName)) { let r2 = regex.exec(e.style.backgroundImage); if (r2 && r2[4] != "orig") { e.style.backgroundImage = r2[1] + r2[2] + r2[3] + "orig" + r2[5]; continue; } continue; } let r = regex.exec(e.getAttribute("src")); if (r && r[4] != "orig") { e.setAttribute("src", r[1] + r[2] + r[3] + "orig" + r[5]); continue; } } }; const XHidepromo = () => { var _a, _b; const SEL = 'path[d^="M19.498 3h-15c-1.381 0-2.5 1.12-2.5 2.5v13c0 1.38 1.119 2.5"]'; const SEL_2 = 'main div[data-testid="sidebarColumn"] section div[data-testid="trend"] div.r-14gqq1x span.css-1qaijid.r-bcqeeo.r-qvutc0'; const SEL_3 = 'main div[data-testid="primaryColumn"] section article span.css-1jxf684.r-bcqeeo.r-qvutc0.r-poiln3'; const SEL_4 = 'main div[data-testid="primaryColumn"] section span.css-901oao.css-16my406.r-bcqeeo.r-qvutc0'; let elms = document.querySelectorAll(SEL); let elms_2 = document.querySelectorAll(SEL_2); let elms_3 = document.querySelectorAll(SEL_3); let elms_4 = document.querySelectorAll(SEL_4); const PROMO = { "ja": "によるプロモーション$", "ko": " 님이 프로모션함$", "zh": "^由 .+ 推广$", "ru": "^Реклама от ", "de": "^Gesponsert von ", "it": "^Sponsorizzato da ", "fr": "^Sponsorisé par ", "pt": "^Promovido por ", "en": "^Promoted by " }; const PROMO_L = (_a = PROMO[ScriptConst.lang]) != null ? _a : PROMO["en"]; const PROMO_2 = { "ja": "プロモポスト", "ko": "Promoted Post", "zh": "推广帖", "ru": "Promoted Post", "de": "Gesponserter Post", "it": "Promoted Post", "fr": "Promoted Post", "pt": "Post promovido", "en": "Promoted Post" }; const PROMO_L_2 = (_b = PROMO_2[ScriptConst.lang]) != null ? _b : PROMO_2["en"]; for (let e of elms) { let xpe = e.closest('div[data-testid="cellInnerDiv"]'); if (!xpe) xpe = e.closest("div.css-175oi2r.r-1adg3ll.r-1ny4l3l"); if (!xpe) xpe = e.closest('div.css-175oi2r.r-1ny4l3l[data-testid="UserCell"]'); if (xpe) xpe.style.setProperty("display", "none"); } for (let e of elms_2) { const REGEX = new RegExp(PROMO_L, "i"); if (!REGEX.test(e.textContent)) continue; let xpe = e.closest("div.css-175oi2r.r-1adg3ll.r-1ny4l3l"); xpe.style.setProperty("display", "none"); } for (let e of elms_3) { if (e.textContent != "Ad") continue; let xpe = e.closest('div[data-testid="cellInnerDiv"]'); xpe.style.setProperty("display", "none"); } for (let e of elms_4) { if (e.textContent != PROMO_2["en"] && e.textContent != PROMO_L_2) continue; let xpe = e.closest('div[data-testid="cellInnerDiv"]'); xpe.style.setProperty("display", "none"); } }; const XDownload = { history: [], show_sensitive: true, filename: "twitter_{user-name}(@{user-id})_{date-time}_{status-id}_{file-type}", css: ` .tmd-down {margin-left: 12px; order: 99;} .tmd-down:hover > div > div > div > div {color: rgba(29, 161, 242, 1.0);} .tmd-down:hover > div > div > div > div > div {background-color: rgba(29, 161, 242, 0.1);} .tmd-down:active > div > div > div > div > div {background-color: rgba(29, 161, 242, 0.2);} .tmd-down:hover svg {color: rgba(29, 161, 242, 1.0);} .tmd-down:hover div:first-child:not(:last-child) {background-color: rgba(29, 161, 242, 0.1);} .tmd-down:active div:first-child:not(:last-child) {background-color: rgba(29, 161, 242, 0.2);} .tmd-down.tmd-media {position: absolute; right: 0;} .tmd-down.tmd-media > div {display: flex; border-radius: 99px; margin: 2px;} .tmd-down.tmd-media > div > div {display: flex; margin: 6px; color: #fff;} .tmd-down.tmd-media:hover > div {background-color: rgba(255,255,255, 0.6);} .tmd-down.tmd-media:hover > div > div {color: rgba(29, 161, 242, 1.0);} .tmd-down.tmd-media:not(:hover) > div > div {filter: drop-shadow(0 0 1px #000);} .tmd-down g {display: none;} .tmd-down.download g.download, .tmd-down.completed g.completed, .tmd-down.loading g.loading,.tmd-down.failed g.failed {display: unset;} .tmd-down.loading svg {animation: spin 1s linear infinite;} @keyframes spin {0% {transform: rotate(0deg);} 100% {transform: rotate(360deg);}} .tmd-btn {display: inline-block; background-color: #1DA1F2; color: #FFFFFF; padding: 0 20px; border-radius: 99px;} .tmd-tag {display: inline-block; background-color: #FFFFFF; color: #1DA1F2; padding: 0 10px; border-radius: 10px; border: 1px solid #1DA1F2; font-weight: bold; margin: 5px;} .tmd-btn:hover {background-color: rgba(29, 161, 242, 0.9);} .tmd-tag:hover {background-color: rgba(29, 161, 242, 0.1);} .tmd-notifier {display: none; position: fixed; left: 16px; bottom: 16px; color: #000; background: #fff; border: 1px solid #ccc; border-radius: 8px; padding: 4px;} .tmd-notifier.running {display: flex; align-items: center;} .tmd-notifier label {display: inline-flex; align-items: center; margin: 0 8px;} .tmd-notifier label:before {content: " "; width: 32px; height: 16px; background-position: center; background-repeat: no-repeat;} .tmd-notifier label:nth-child(1):before {background-image:url("data:image/svg+xml;charset=utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2216%22 height=%2216%22 viewBox=%220 0 24 24%22><path d=%22M3,14 v5 q0,2 2,2 h14 q2,0 2,-2 v-5 M7,10 l4,4 q1,1 2,0 l4,-4 M12,3 v11%22 fill=%22none%22 stroke=%22%23666%22 stroke-width=%222%22 stroke-linecap=%22round%22 /></svg>");} .tmd-notifier label:nth-child(2):before {background-image:url("data:image/svg+xml;charset=utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2216%22 height=%2216%22 viewBox=%220 0 24 24%22><path d=%22M12,2 a1,1 0 0 1 0,20 a1,1 0 0 1 0,-20 M12,5 v7 h6%22 fill=%22none%22 stroke=%22%23999%22 stroke-width=%222%22 stroke-linejoin=%22round%22 stroke-linecap=%22round%22 /></svg>");} .tmd-notifier label:nth-child(3):before {background-image:url("data:image/svg+xml;charset=utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2216%22 height=%2216%22 viewBox=%220 0 24 24%22><path d=%22M12,0 a2,2 0 0 0 0,24 a2,2 0 0 0 0,-24%22 fill=%22%23f66%22 stroke=%22none%22 /><path d=%22M14.5,5 a1,1 0 0 0 -5,0 l0.5,9 a1,1 0 0 0 4,0 z M12,17 a2,2 0 0 0 0,5 a2,2 0 0 0 0,-5%22 fill=%22%23fff%22 stroke=%22none%22 /></svg>");} .tmd-down.tmd-img {position: absolute; right: 0; bottom: 0; display: none !important;} .tmd-down.tmd-img > div {display: flex; border-radius: 99px; margin: 2px; background-color: rgba(255,255,255, 0.6);} .tmd-down.tmd-img > div > div {display: flex; margin: 6px; color: #fff !important;} .tmd-down.tmd-img:not(:hover) > div > div {filter: drop-shadow(0 0 1px #000);} .tmd-down.tmd-img:hover > div > div {color: rgba(29, 161, 242, 1.0);} :hover > .tmd-down.tmd-img, .tmd-img.loading, .tmd-img.completed, .tmd-img.failed {display: block !important;} .tweet-detail-action-item {width: 20% !important;} `, css_ss: ` /* show sensitive in media tab */ li[role="listitem"]>div>div>div>div:not(:last-child) {filter: none;} li[role="listitem"]>div>div>div>div+div:last-child {display: none;} `, svg: ` <g class="download"><path d="M3,14 v5 q0,2 2,2 h14 q2,0 2,-2 v-5 M7,10 l4,4 q1,1 2,0 l4,-4 M12,3 v11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></g> <g class="completed"><path d="M3,14 v5 q0,2 2,2 h14 q2,0 2,-2 v-5 M7,10 l3,4 q1,1 2,0 l8,-11" fill="none" stroke="#1DA1F2" stroke-width="2" stroke-linecap="round" /></g> <g class="loading"><circle cx="12" cy="12" r="10" fill="none" stroke="#1DA1F2" stroke-width="4" opacity="0.4" /><path d="M12,2 a10,10 0 0 1 10,10" fill="none" stroke="#1DA1F2" stroke-width="4" stroke-linecap="round" /></g> <g class="failed"><circle cx="12" cy="12" r="11" fill="#f33" stroke="currentColor" stroke-width="2" opacity="0.8" /><path d="M14,5 a1,1 0 0 0 -4,0 l0.5,9.5 a1.5,1.5 0 0 0 3,0 z M12,17 a2,2 0 0 0 0,4 a2,2 0 0 0 0,-4" fill="#fff" stroke="none" /></g> `, isTweetdeck: function() { return ScriptConst.currentHost.indexOf("tweetdeck") >= 0; }, getCookie: function() { const cookieString = document.cookie; const cookiePairs = cookieString.split(";"); const cookiesObject = {}; for (const pair of cookiePairs) { const [key, value] = pair.split("="); cookiesObject[key.trim()] = value.trim(); } return cookiesObject; }, formatDate: function(i, o, tz) { let d = new Date(i); if (tz) { d.setMinutes(d.getMinutes() - d.getTimezoneOffset()); } let m = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]; let v = { YYYY: d.getUTCFullYear().toString(), YY: d.getUTCFullYear().toString(), MM: d.getUTCMonth() + 1, MMM: m[d.getUTCMonth()], DD: d.getUTCDate(), hh: d.getUTCHours(), mm: d.getUTCMinutes(), ss: d.getUTCSeconds(), h2: d.getUTCHours() % 12, ap: d.getUTCHours() < 12 ? "AM" : "PM" }; return o.replace(/(YY(YY)?|MMM?|DD|hh|mm|ss|h2|ap)/g, (n) => ("0" + v[n]).substr(-n.length)); }, detect: function(node) { let article = node.tagName == "ARTICLE" && node || node.tagName == "DIV" && (node.querySelector("article") || node.closest("article")); if (article) { this.addButtonTo(article); } let listitems = node.tagName == "LI" && node.getAttribute("role") == "listitem" && [node] || node.tagName == "DIV" && node.querySelectorAll('li[role="listitem"]'); if (listitems) { this.addButtonToMedia(listitems); } }, addButtonTo: function(article) { if (article.dataset.detected) { return; } article.dataset.detected = "true"; const media_selector = [ 'a[href*="/photo/1"]', 'div[role="progressbar"]', 'button[data-testid="playButton"]', '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 media = article.querySelector(media_selector.join(",")); if (media) { let status_id2 = article.querySelector('a[href*="/status/"]').href.split("/status/").pop().split("/").shift(); let btn_group = article.querySelector('div[role="group"]:last-of-type, ul.tweet-actions, ul.tweet-detail-actions'); let btn_share = Array.from(btn_group.querySelectorAll(":scope>div>div, li.tweet-action-item>a, li.tweet-detail-action-item>a")).pop().parentNode; let btn_down = btn_share.cloneNode(true); btn_down.querySelector("button").removeAttribute("disabled"); if (this.isTweetdeck()) { btn_down.firstElementChild.innerHTML = '<svg viewBox="0 0 24 24" style="width: 18px; height: 18px;">' + this.svg + "</svg>"; btn_down.firstElementChild.removeAttribute("rel"); btn_down.classList.replace("pull-left", "pull-right"); } else { btn_down.querySelector("svg").innerHTML = this.svg; } let is_exist = this.history.indexOf(status_id2) >= 0; this.status(btn_down, "tmd-down"); this.status(btn_down, is_exist ? "completed" : "download", is_exist ? Commonlanguage.download.completed : Commonlanguage.download.download); btn_group.insertBefore(btn_down, btn_share.nextSibling); btn_down.onclick = () => { this.click(btn_down, status_id2, is_exist); }; if (this.show_sensitive) { let btn_show = article.querySelector('div[aria-labelledby] div[role="button"][tabindex="0"]:not([data-testid]) > div[dir] > span > span'); if (btn_show) { btn_show.click(); } } } const imgs = article.querySelectorAll('a[href*="/photo/"]'); if (imgs.length > 1) { let status_id2 = article.querySelector('a[href*="/status/"]').href.split("/status/").pop().split("/").shift(); let btn_group = article.querySelector('div[role="group"]:last-of-type'); Array.from(btn_group.querySelectorAll(":scope>div>div")).pop().parentNode; imgs.forEach((img) => { let index = img.href.split("/status/").pop().split("/").pop(); let is_exist = this.history.indexOf(status_id2) >= 0; let btn_down = document.createElement("div"); btn_down.innerHTML = '<div><div><svg viewBox="0 0 24 24" style="width: 18px; height: 18px;">' + this.svg + "</svg></div></div>"; btn_down.classList.add("tmd-down", "tmd-img"); this.status(btn_down, "download"); img.parentNode.appendChild(btn_down); btn_down.onclick = (e) => { e.preventDefault(); this.click(btn_down, status_id2, is_exist, index); }; }); } }, addButtonToMedia: function(listitems) { listitems.forEach((li) => { if (li.dataset.detected) return; li.dataset.detected = "true"; let is_exist = false; try { let status_id2 = li.querySelector('a[href*="/status/"]').href.split("/status/").pop().split("/").shift(); is_exist = this.history.indexOf(status_id2) >= 0; } catch (e) { } let btn_down = document.createElement("div"); btn_down.innerHTML = '<div><div><svg viewBox="0 0 24 24" style="width: 18px; height: 18px;">' + this.svg + "</svg></div></div>"; btn_down.classList.add("tmd-down", "tmd-media"); this.status(btn_down, is_exist ? "completed" : "download", is_exist ? Commonlanguage.download.completed : Commonlanguage.download.download); li.appendChild(btn_down); btn_down.onclick = () => { this.click(btn_down, status_id, is_exist); }; }); }, status: function(btn, css, title, style) { if (css) { btn.classList.remove("download", "completed", "loading", "failed"); btn.classList.add(css); } if (title) btn.title = title; if (style) btn.style.cssText = style; }, fetchJson: function(status_id2) { return __async$2(this, null, function* () { const base_url = `https://${ScriptConst.currentHost}/i/api/graphql/NmCeCgkVlsRGS1cAwqtgmw/TweetDetail`; const variables = { "focalTweetId": status_id2, "with_rux_injections": false, "includePromotedContent": true, "withCommunity": true, "withQuickPromoteEligibilityTweetFields": true, "withBirdwatchNotes": true, "withVoice": true, "withV2Timeline": true }; const features = { "rweb_lists_timeline_redesign_enabled": true, "responsive_web_graphql_exclude_directive_enabled": true, "verified_phone_label_enabled": false, "creator_subscriptions_tweet_preview_api_enabled": true, "responsive_web_graphql_timeline_navigation_enabled": true, "responsive_web_graphql_skip_user_profile_image_extensions_enabled": false, "tweetypie_unmention_optimization_enabled": true, "responsive_web_edit_tweet_api_enabled": true, "graphql_is_translatable_rweb_tweet_is_translatable_enabled": true, "view_counts_everywhere_api_enabled": true, "longform_notetweets_consumption_enabled": true, "responsive_web_twitter_article_tweet_consumption_enabled": false, "tweet_awards_web_tipping_enabled": false, "freedom_of_speech_not_reach_fetch_enabled": true, "standardized_nudges_misinfo": true, "tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled": true, "longform_notetweets_rich_text_read_enabled": true, "longform_notetweets_inline_media_enabled": true, "responsive_web_media_download_video_enabled": false, "responsive_web_enhance_cards_enabled": false }; const url = encodeURI(`${base_url}?variables=${JSON.stringify(variables)}&features=${JSON.stringify(features)}`); const cookies = this.getCookie(); const headers = { "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA", "x-twitter-active-user": "yes", "x-twitter-client-language": cookies.lang, "x-csrf-token": cookies.ct0 }; if (cookies.ct0.length == 32) headers["x-guest-token"] = cookies.gt; let tweet_detail = yield fetch(url, { headers }).then((result) => result.json()); let tweet_entrie = tweet_detail.data.threaded_conversation_with_injections_v2.instructions[0].entries.find((n) => n.entryId == `tweet-${status_id2}`); let tweet_result = tweet_entrie.content.itemContent.tweet_results.result; return tweet_result.tweet || tweet_result; }); }, click: function(btn, status_id2, is_exist, index) { return __async$2(this, null, function* () { if (btn.classList.contains("loading")) return; this.status(btn, "loading"); let save_history = yield GM_getValue("save_history", true); let json = yield this.fetchJson(status_id2); let tweet = json.legacy; let user = json.core.user_results.result.legacy; let invalid_chars = { "\\": "\", "/": "/", "|": "|", "<": "<", ">": ">", ":": ":", "*": "*", "?": "?", '"': """, "": "", "": "", "": "", "": "", "\uFEFF": "", "🔞": "" }; let datetime = this.filename.match(/{date-time(-local)?:[^{}]+}/) ? this.filename.match(/{date-time(?:-local)?:([^{}]+)}/)[1].replace(/[\\/ | <>*?:"]/g, (v) => invalid_chars[v]) : "YYYYMMDD-hhmmss"; let info = {}; info["status-id"] = status_id2; info["user-name"] = user.name.replace(/([\\/|*?:"] | [\u200b - \u200d\u2060\ufeff] | 🔞) /g, (v) => invalid_chars[v]); info["user-id"] = user.screen_name; info["date-time"] = this.formatDate(tweet.created_at, datetime); info["date-time-local"] = this.formatDate(tweet.created_at, datetime, true); info["full-text"] = tweet.full_text.split("\n").join(" ").replace(/\s*https:\/\/t\.co\/\w+/g, "").replace(/[\\/ | <>*?:"]|[\u200b-\u200d\u2060\ufeff]/g, (v) => invalid_chars[v]); let medias = tweet.extended_entities && tweet.extended_entities.media; if (!medias || medias.length == 0) { try { medias = JSON.parse(json.card.legacy.binding_values[0].value.string_value).media_entities; medias = Object.values(medias); } catch (e) { } } if (!medias || medias.length == 0) { this.status(btn, "failed", "MEDIA_NOT_FOUND"); return; } if (index) { medias = [medias[index - 1]]; } if (medias.length > 0) { let tasks = medias.length; let tasks_result = []; medias.forEach((media, i) => { info.url = media.type == "photo" ? media.media_url_https + ":orig" : media.video_info.variants.filter((n) => n.content_type == "video/mp4").sort((a, b) => b.bitrate - a.bitrate)[0].url; info.file = info.url.split("/").pop().split(/[:?]/).shift(); info["file-name"] = info.file.split(".").shift(); info["file-ext"] = info.file.split(".").pop(); info["file-type"] = media.type.replace("animated_", ""); info.out = (this.filename.replace(/\.?{file-ext}/, "") + ((medias.length > 1 || index) && !this.filename.match("{file-name}") ? "-" + (index ? index - 1 : i) : "") + ".{file-ext}").replace(/{([^{}:]+)(:[^{}]+)?}/g, (match, name) => info[name]); this.downloader.add({ url: info.url, name: info.out, onload: () => { tasks -= 1; tasks_result.push((medias.length > 1 || index ? (index ? index : i + 1) + ": " : "") + Commonlanguage.download.completed); this.status(btn, null, tasks_result.sort().join("\n")); if (tasks === 0) { this.status(btn, "completed", Commonlanguage.download.completed); if (save_history && !is_exist) { this.history.push(status_id2); } } }, onerror: (result) => { tasks = -1; tasks_result.push((medias.length > 1 ? i + 1 + ": " : "") + result.details.current); this.status(btn, "failed", tasks_result.sort().join("\n")); } }); }); } else { this.status(btn, "failed", "MEDIA_NOT_FOUND"); } }); }, downloader: function() { let tasks = [], thread = 0, max_thread = 2, retry = 0, max_retry = 2, failed = 0, notifier, has_failed = false; return { add: function(task) { tasks.push(task); if (thread < max_thread) { thread += 1; this.next(); } else { this.update(); } }, next: function() { return __async$2(this, null, function* () { let task = tasks.shift(); yield this.start(task); if (tasks.length > 0 && thread <= max_thread) { this.next(); } else { thread -= 1; } this.update(); }); }, start: function(task) { this.update(); return new Promise((resolve) => { GM_download({ url: task.url, name: task.name, onload: (result) => { task.onload(); resolve(); }, onerror: (result) => { this.retry(task, result); resolve(); }, ontimeout: (result) => { this.retry(task, result); resolve(); } }); }); }, retry: function(task, result) { retry += 1; if (retry == 3) max_thread = 1; if (task.retry && task.retry >= max_retry || result.details && result.details.current == "USER_CANCELED") { task.onerror(result); failed += 1; } else { if (max_thread == 1) task.retry = (task.retry || 0) + 1; this.add(task); } }, update: function() { if (!notifier) { notifier = document.createElement("div"); notifier.title = "Twitter Media Downloader"; notifier.classList.add("tmd-notifier"); notifier.innerHTML = "<label>0</label>|<label>0</label>"; document.body.appendChild(notifier); } if (failed > 0 && !has_failed) { has_failed = true; notifier.innerHTML += "|"; let clear = document.createElement("label"); notifier.appendChild(clear); clear.onclick = () => { notifier.innerHTML = "<label>0</label>|<label>0</label>"; failed = 0; has_failed = false; this.update(); }; } notifier.firstChild.innerText = thread; notifier.firstChild.nextElementSibling.innerText = tasks.length; if (failed > 0) { notifier.lastChild.innerText = failed; } if (thread > 0 || tasks.length > 0 || failed > 0) { notifier.classList.add("running"); } else { notifier.classList.remove("running"); } } }; }(), init: function() { document.head.insertAdjacentHTML("beforeend", "<style>" + this.css + (this.show_sensitive ? this.css_ss : "") + "</style>"); } }; const X = { XSettingsDialog, XDateFormat, XOrigimg, XHidepromo, XDownload }; var __async$1 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const Tiktok = { extractHref: function(html) { const regex = /<a\s+(?:[^>]*?\s+)?href=(['"])(.*?)\1/gi; const hrefs = []; let match; while ((match = regex.exec(html)) !== null) { hrefs.push(match[2]); } return hrefs.filter((href) => href.indexOf("snapcdn.app") != -1); }, download: function(url, element) { return __async$1(this, null, function* () { Toast.show({ "message": Commonlanguage.download.preparing, "background": "#000" }); element.classList.add("download-loadding"); const param = new URLSearchParams({ lang: "en", q: url }).toString(); const data = yield Tools.request("POST", "https://tikdownloader.io/api/ajaxSearch", param, { "Content-Type": "application/x-www-form-urlencoded" }); if (data.code === "success") { const result = JSON.parse(data.result); if (result.status == "ok" && result.hasOwnProperty("data")) { const data2 = result.data; const downloadUrls = this.extractHref(data2); if (downloadUrls.length >= 2) { Tools.openInTab(downloadUrls.at(-2)); } } } element.classList.remove("download-loadding"); }); }, start: function() { return __async$1(this, null, function* () { if (!/www\.tiktok\.com/.test(window.location.host)) { return; } GM_addStyle(` @keyframes scriptspin {0% {transform: rotate(0deg);} 100% {transform: rotate(360deg);}} .download-loadding{ animation: scriptspin 1s linear infinite; } `); setInterval(() => { if (!document.querySelector("#tiktok-download-990i")) { const container = document.querySelector("#main-content-video_detail") || document.body; if (!container) { return; } const divs = container.querySelectorAll("div"); const regex = /-DivRightControlsWrapper|-DivMiniPlayerContainer/; const matchedDiv = Array.from(divs).find((div) => { return div.classList.value.split(" ").some((className) => { return regex.test(className); }); }); if (matchedDiv) { let cloneNode = null; let isDetail = matchedDiv.children.length != 1; if (isDetail) { cloneNode = matchedDiv.children[0].cloneNode(true); } else { cloneNode = matchedDiv.cloneNode(true); } cloneNode.id = "tiktok-download-990i"; cloneNode.querySelector("div").innerHTML = `<svg t="1724300009050" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5307" width="35" height="35"><path d="M298.666667 554.666667v85.333333H256v128h512v-128h-42.666667v-85.333333h128v213.333333a85.333333 85.333333 0 0 1-78.933333 85.077333L768 853.333333H256a85.333333 85.333333 0 0 1-85.12-78.933333L170.666667 768v-213.333333h128z" fill="#ffffff" p-id="5308"></path><path d="M512 627.498667l219.477333-219.477334h-120.704L512 506.88 413.141333 408.021333H292.522667L512 627.498667z" fill="#ffffff" p-id="5309"></path><path d="M554.666667 528V167.978667h-85.333334v360.021333h85.333334z" fill="#ffffff" p-id="5310"></path></svg>`; if (isDetail) { matchedDiv.insertBefore(cloneNode, matchedDiv.children[0]); } else { cloneNode.style.right = 166 + "px"; matchedDiv.parentNode.insertBefore(cloneNode, matchedDiv); } cloneNode.title = Commonlanguage.download.tip; cloneNode.addEventListener("click", () => { Tiktok.download(window.location.href, cloneNode); }); } } }, 1500); }); } }; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const YoutubeDownload = { markName: `script-download-----iux998htt`, isComplete: true, download: function(btn) { return __async(this, null, function* () { try { btn.classList.add("download-loadding"); const downloadUl = yield this.getDownloadUrl(window.location.href.replace("music.youtube.com", "www.youtube.com")); window.open(downloadUl, "_blank"); } catch (ex) { } finally { btn.classList.remove("download-loadding"); } }); }, getDownloadUrl: function(videoUrl, audioOnly = false) { return new Promise((resolve, reject) => { resolve("https://cobalt.tools/?url=" + videoUrl); }); }, elementInContainer: function(container, element) { return container.contains(element); }, detectYoutubeService: function() { if (window.location.hostname === "www.youtube.com" && window.location.pathname.startsWith("/shorts")) return "shorts"; if (window.location.hostname === "www.youtube.com" && window.location.pathname.startsWith("/watch")) return "watch"; else if (window.location.hostname === "music.youtube.com") return "music"; else if (window.location.hostname === "www.youtube.com") return "youtube"; else return null; }, hookNavigationEvents: function() { return __async(this, null, function* () { ["yt-navigate", "yt-navigate-finish", "yt-navigate-finish", "yt-page-data-updated"].forEach((evName) => { if (evName) { document.addEventListener(evName, (e) => { this.appendDownloadButton(e); }); } }); }); }, appendDownloadButton: function(e) { return __async(this, null, function* () { try { this.isComplete = false; const ytContainerSelector = "#movie_player > div.ytp-chrome-bottom > div.ytp-chrome-controls > div.ytp-right-controls"; const ytmContainerSelector = "#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.middle-controls-buttons.style-scope.ytmusic-player-bar"; const img = document.createElement("img"); img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAepJREFUaEPtmEFygzAMRQ3dsm2mx0kOkfO0OQ+HCL1Np91m29ARtgM0gPUluZ3MmE0miSH//S8Jk8o9+FE9uH5XAP47wZJASUDpQCkhpYHq00sCSxY27ct+/Py6d67u6P3l+DG8Wh5mCXjR369eXDUBuJN78jCfbxYgaoBR+KboJa0nCwgVgBd/PSudVIGIAZp2RyUQSkaJ4JwYQgRgLD7SiyCkAD3P8z5MHW5/1Ad0UsEAgPs3R5v2+ZyYTMGPvrscvw48c8K8QxYD4umyEwCkX7AUoAT+BgBLAQVg1v6QqzCB4SbH1sVeKJj5YgDn+GVkDEBTp3r3fVV3caIE+On2InH/yALAasTkLOf1URYA9rZhFYInft4/qSlpXELx5+4dBMRT+bFvaJkA5pMEHwAZAMhb/h2VVo/zvGl3yPjNM0ZxAA/B20LMKj05CKar2SXkAbYamcQ+DU9b6YMeM1e34vkAtlJA7p7+OotlBYmn60AJJFJg//jaREJNEAEE9yyfxmLFsQ0Q98D0RGyuJ7tCJF6cQJRjBCEWrwbQgfiphT5C/s4SbuK1Yghp0NcbO834jKwXHnWYAcz7I/61OP6tSN9r3V4yLwtAsmUNFxQAQzNFlyoJiGwzPKkkYGim6FIlAZFthic9fAI/mIfoMZ8JBO0AAAAASUVORK5CYII="; img.style.width = "44px"; img.style.height = "44px"; const markName = this.markName; if (document.querySelector("." + markName)) return; const escapeHTMLPolicy = trustedTypes.createPolicy("conardEscapePolicy", { createHTML: (string) => string.replace(/\</g, "<") }); const downloadButton = document.createElement("button"); downloadButton.id = "ytdl-download-button"; downloadButton.classList.add("ytp-button", markName); downloadButton.title = Commonlanguage.download.tip; downloadButton.style.borderRadius = "50%"; downloadButton.appendChild(img); switch (this.detectYoutubeService()) { case "watch": const ytCont = yield Tools.waitForElementByInterval(ytContainerSelector); if (this.elementInContainer(ytCont, ytCont.querySelector("#ytdl-download-button"))) { break; } const ytDlBtnClone = downloadButton.cloneNode(true); ytDlBtnClone.classList.add("YT"); ytDlBtnClone.addEventListener("click", () => { this.download(ytDlBtnClone); }); ytCont.insertBefore(ytDlBtnClone, ytCont.firstChild); break; case "shorts": if (!document.querySelector("#navigation-button-download-----iux998htt")) { const navigationButtonDown = document.querySelector("#navigation-button-down"); const navigationButtonDownload = navigationButtonDown.cloneNode(false); navigationButtonDownload.id = "navigation-button-download-----iux998htt"; navigationButtonDownload.style.textAlign = "center"; navigationButtonDownload.appendChild(img); document.querySelector(".navigation-container").appendChild(navigationButtonDownload); navigationButtonDownload.addEventListener("click", () => { this.download(img); }); } break; case "music": const ytmCont = yield Tools.waitForElementByInterval(ytmContainerSelector); if (this.elementInContainer(ytmCont, ytmCont.querySelector("#ytdl-download-button"))) { break; } const ytmDlBtnClone = downloadButton.cloneNode(true); ytmDlBtnClone.classList.add("YTM"); ytmDlBtnClone.addEventListener("click", () => { this.download(ytmDlBtnClone); }); ytmCont.insertBefore(ytmDlBtnClone, ytmCont.firstChild); break; default: return; } } catch (error) { } finally { this.isComplete = true; } }); }, initStyle: function() { GM_addStyle(` @keyframes scriptspin {0% {transform: rotate(0deg);} 100% {transform: rotate(360deg);}} .download-loadding{ animation: scriptspin 1s linear infinite; } `); }, asyncAppendDownloadButton: function() { let allDelay = 1e3 * 30, delay = 250; const interval = setInterval(() => { if (document.querySelector("." + this.markName) || allDelay <= 0) { clearInterval(interval); } else { if (this.isComplete) this.appendDownloadButton(); } allDelay -= delay; }, delay); }, start: function() { this.initStyle(); let currentUrl = null; setInterval(() => { const visitUrl = window.location.href; if (currentUrl !== window.location.href) { currentUrl = window.location.href; const watch = /www\.youtube\.com\/watch\?v=/.test(visitUrl); const shorts = /www\.youtube\.com\/shorts\//.test(visitUrl); const music = /music\.youtube\.com\/watch\?v=/.test(visitUrl); if (watch || shorts || music) { this.hookNavigationEvents(); this.asyncAppendDownloadButton(); } } }, 500); } }; const CobaltDownloader = { start: function() { const params = new URLSearchParams(window.location.search); const url = params.get("url"); if (url) { GM_setClipboard(url, "txt", () => { Toast.show({ "message": Commonlanguage.download.preparing, "background": "#000", "time": 3e3 }); setTimeout(() => { const buttonPaste = document.querySelector("#button-paste"); if (buttonPaste) { buttonPaste.click(); document.querySelector("#link-area").value = url; const downloadButton = document.querySelector("#download-button"); if (downloadButton) { setTimeout(() => { downloadButton.click(); }, 2e3); } } }, 2e3); }); } } }; const LimitModules = { CobaltDownloader, X, Youtube: { YoutubeDownload }, Tiktok }; const Init = { x: function() { LimitModules.X.XDownload.init(); LimitModules.X.XSettingsDialog.init(); const observer = new MutationObserver((ms) => ms.forEach((m) => { m.addedNodes.forEach((node) => { LimitModules.X.XDownload.detect(node); LimitModules.X.XDateFormat.repldatetime(); LimitModules.X.XOrigimg(); LimitModules.X.XHidepromo(); }); })); observer.observe(document.body, { childList: true, subtree: true }); }, youtube: function() { LimitModules.Youtube.YoutubeDownload.start(); }, tiktok: function() { LimitModules.Tiktok.start(); }, cobalt: function() { LimitModules.CobaltDownloader.start(); }, unknown: function() { }, start: function() { const otherPlatform = Tools.getOtherPlatform(); if (otherPlatform) { try { this[otherPlatform](); } catch (e) { console.log("error", "Hoooo,catch", e); } } } }; Init.start(); }());