// ==UserScript== // @name 短视频下载助手,为抖音、快手、小红书等提供无水印高清下载功能 // @namespace huahuacat_nowater_downloader // @version 1.0.2 // @description 视频下载助手:1、支持抖音短视频下载:为首页、搜索结果、用户主页等提供无水印视频下载功能;2、快手短视频下载:为视频详情页提供无水印视频下载功能;其他平台持续开发中【脚本长期维护更新,完全免费,无广告】 // @author 爱画画的猫,潮玩天下 // @include https://www.douyin.com/* // @include https://www.kuaishou.com/* // @connect www.iesdouyin.com // @grant unsafeWindow // @grant GM_openInTab // @grant GM.openInTab // @grant GM_xmlhttpRequest // @grant GM.xmlHttpRequest // @license AGPL License // @charset UTF-8 // @original-author 爱画画的猫 // @original-license AGPL License // @original-script https://greasyfork.org/zh-CN/scripts/418804 // @run-at document-idle // @downloadURL none // ==/UserScript== (function () { /** * 此工具方法来自画画的猫 * 脚本地址:https://greasyfork.org/zh-CN/scripts/418804 */ //共有方法,全局共享 function commonFunction(){ this.GMgetValue = function (name, value=null) { let storageValue = value; if (typeof GM_getValue === "function") { storageValue = GM_getValue(name, value); } else if(typeof GM.setValue === "function"){ storageValue = GM.getValue(name, value); }else{ var arr = window.localStorage.getItem(name); if(arr != null){ storageValue = arr } } return storageValue; }; this.GMsetValue = function(name, value){ if (typeof GM_setValue === "function") { GM_setValue(name, value); } else if(typeof GM.setValue === "function"){ GM.setValue(name, value); }else{ window.localStorage.setItem(name, value) } }; this.GMaddStyle = function(css){ var myStyle = document.createElement('style'); myStyle.textContent = css; var doc = document.head || document.documentElement; doc.appendChild(myStyle); }; this.GMopenInTab = function(url, options={"active":true, "insert":true, "setParent":true}){ if (typeof GM_openInTab === "function") { GM_openInTab(url, options); } else { GM.openInTab(url, options); } }; this.addScript = function(url){ var s = document.createElement('script'); s.setAttribute('src',url); document.body.appendChild(s); }; this.randomNumber = function(){ return Math.ceil(Math.random()*100000000); }; this.request = function(mothed, url, param){ //网络请求 return new Promise(function(resolve, reject){ GM_xmlhttpRequest({ url: url, method: mothed, data:param, onload: function(response) { var status = response.status; var playurl = ""; if(status==200||status=='200'){ var responseText = response.responseText; resolve({"result":"success", "data":responseText}); }else{ reject({"result":"error", "data":null}); } } }); }) }; this.addCommonHtmlCss = function(){ var cssText = ` @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} } .web-toast-kkli9{ 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; } `; this.GMaddStyle(cssText); }; this.webToast = function(params) { //小提示框 var time = params.time; var background = params.background; var color = params.color; var position = params.position; //center-top, center-bottom var defaultMarginValue = 50; if(time == undefined || time == ''){ time = 1500; } var el = document.createElement("div"); el.setAttribute("class", "web-toast-kkli9"); el.innerHTML = params.message; //背景颜色 if(background!=undefined && background!=''){ el.style.backgroundColor=background; } //字体颜色 if(color!=undefined && color!=''){ el.style.color=color; } //显示位置 if(position==undefined || position==''){ position = "center-bottom"; } //设置显示位置,当前有种两种形式 if(position==="center-bottom"){ el.style.bottom = defaultMarginValue+"px"; }else{ el.style.top = defaultMarginValue+"px"; } el.style.zIndex=999999; document.body.appendChild(el); el.classList.add("fadeIn"); setTimeout(function () { el.classList.remove("fadeIn"); el.classList.add("fadeOut"); /*监听动画结束,移除提示信息元素*/ el.addEventListener("animationend", function () { document.body.removeChild(el); }); el.addEventListener("webkitAnimationEnd", function () { document.body.removeChild(el); }); }, time); }; this.queryUrlParamter = function(text, tag) { //查询GET请求url中的参数 if(text.indexOf("?")!=-1){ //选取?后面的字符串,兼容window.location.search,前面的?不能去掉 var textArray = text.split("?"); text = "?"+textArray[textArray.length-1]; } var t = new RegExp("(^|&)" + tag + "=([^&]*)(&|$)"); var a = text.substr(1).match(t); if (a != null){ return a[2]; } return ""; }; this.isPC = function(){ var userAgentInfo = navigator.userAgent; var Agents = ["Android", "iPhone","SymbianOS", "Windows Phone", "iPad", "iPod"]; var flag = true; for (var v = 0; v < Agents.length; v++) { if (userAgentInfo.indexOf(Agents[v]) > 0) { flag = false; break; } } return flag; }; this.getBilibiliBV=function(){ var pathname = window.location.pathname; var bv = pathname.replace("/video/","").replace("/",""); return bv; }; this.getSystemOS=function(){ var u = navigator.userAgent; if (!!u.match(/compatible/i) || u.match(/Windows/i)) { return 'windows'; } else if (!!u.match(/Macintosh/i) || u.match(/MacIntel/i)) { return 'macOS'; } else if (!!u.match(/iphone/i) || u.match(/Ipad/i)) { return 'ios'; } else if (!!u.match(/android/i)) { return 'android'; } else { return 'other'; } }; this.RPCDownloadFile = function(fileName, url, savePath="D:/", RPCURL="ws://localhost:16800/jsonrpc", RPCToken="") { const self = this; if(!savePath){ savePath = "D:/"; } if(!RPCURL){ RPCURL = "ws://localhost:16800/jsonrpc"; } let options = { //下载配置文件 "dir":savePath, "max-connection-per-server": "16", "header":["User-Agent:"+navigator.userAgent+"", "Cookie:"+document.cookie+"", "Referer:"+window.location.href+""] } if(!!fileName) { options.out = fileName; } let jsonRPC = { "jsonrpc": "2.0", "id": "huahuacat", "method": "aria2.addUri", "params": [[url], options], } if (!!RPCToken) { jsonRPC.params.unshift("token:" + RPCToken); // 必须要加在第一个 } return new Promise(function(resolve, reject) { var webSocket = new WebSocket(RPCURL); webSocket.onerror = function(event) { console.log("webSocket.onerror", event); reject("Aria2连接错误,请打开Aria2和检查RPC设置!"); } webSocket.onopen = function(){ webSocket.send(JSON.stringify(jsonRPC)); } webSocket.onmessage = function(event){ let result = JSON.parse(event.data); switch (result.method) { case "aria2.onDownloadStart": resolve("Aria2 开始下载【"+fileName+"】"); webSocket.close(); break; case "aria2.onDownloadComplete": break; default: break; } } }); }; this.getElementObject = function(selector, delay=200){ return new Promise((resolve,reject) =>{ let totalDelay = 0; let elementInterval = setInterval(()=>{ if(totalDelay >= 2500){ reject(false); clearInterval(elementInterval); } let element = document.querySelector(selector); if(element){ resolve(element); clearInterval(elementInterval); }else{ totalDelay += delay; } }, delay); }); }; } //统一工具 const commonFunctionObject = new commonFunction(); commonFunctionObject.addCommonHtmlCss(); //统一html、css元素添加 function shortVideoDownloader(){ this.douyinVideoDownloader = function(){ if(window.location.host !== "www.douyin.com"){ return; } window.addEventListener('load',function(){ //这是搜索界面 if(window.location.href.match(/https:\/\/www\.douyin\.com\/search\/.*?/)){ function downloader(){ const videoContainers = document.querySelectorAll(".player-info"); videoContainers.forEach((element)=>{ if(element.getAttribute("dealwith")){ return; } let bottomMenu = element.querySelector('xg-right-grid'); if(!bottomMenu){ return; } let playbackSetting = bottomMenu.querySelector('.xgplayer-playback-setting'); if(!playbackSetting){ return; } let download = playbackSetting.cloneNode(true); // 拷贝一个节点 let downloadText = download.querySelector('div:first-child'); let video = element.querySelector("video"); downloadText.innerText='下载'; downloadText.style = 'font-size:13px'; playbackSetting.after(download); element.setAttribute("dealwith","true"); download.addEventListener("click",(e)=>{ let playerUrl = video.children[0].src; commonFunctionObject.GMopenInTab(playerUrl); }); }); } downloader(); setInterval(function(){ downloader(); },500); }else{ async function downloader(){ try{ //延迟加载等到是否完成 let videoContainer = await commonFunctionObject.getElementObject(".xg-video-container"); if(!videoContainer){ return false; } let bottomMenus = document.querySelectorAll('.xg-right-grid'); let bottomMenuLength = bottomMenus.length; let bottomMenu = bottomMenus.length>1 ? bottomMenus[bottomMenuLength - 2] : bottomMenus[bottomMenuLength - 1]; let douyinVideoDownloaderDom = document.querySelector('#douyin-video-downloder'); if(douyinVideoDownloaderDom){ douyinVideoDownloaderDom.parentNode.parentNode.removeChild(douyinVideoDownloaderDom.parentNode); } // 拷贝一个节点 let playbackSetting = bottomMenu.querySelector('.xgplayer-playback-setting'); if(!playbackSetting){ return false; } let download = playbackSetting.cloneNode(true); let downloadText = download.querySelector('div:first-child'); downloadText.innerText='下载'; downloadText.style = 'font-size:14px'; downloadText.setAttribute('id','douyin-video-downloder'); let autoplaySetting = document.querySelector('.xgplayer-autoplay-setting'); if(!autoplaySetting){ return false; } autoplaySetting.after(download); let videoPlayers = document.querySelectorAll('video'); let videoPlayDom = videoPlayers[videoPlayers.length>1 ? videoPlayers.length-2 : videoPlayers.length-1]; document.querySelector("#douyin-video-downloder").addEventListener("click", (e)=>{ let playerUrl = videoPlayDom.children[0].src; commonFunctionObject.GMopenInTab(playerUrl); }); }catch(e){} } //监听鼠标 window.addEventListener("wheel",downloader); window.addEventListener('keydown',function(e){ if(e.code=='ArrowDown' || e.code=='ArrowUp'){ downloader(); } }); //视频改变后触发 async function domNodeInserted(){ let findVideoInterval = setInterval(function(){ let videoElement = document.querySelector("video"); if(videoElement){ videoElement.addEventListener('DOMNodeInserted',(e) => { downloader(); }); clearInterval(findVideoInterval); } }, 200); } domNodeInserted(); downloader(); } }); }; this.kuaishouVideoDownloader = function(){ if(window.location.host !== "www.kuaishou.com"){ return; } window.addEventListener('load',function(){ async function downloader(){ let kuaishouVideoDownloder = document.querySelector("#kuaishou-video-downloder"); if(!kuaishouVideoDownloder){ let downloadDIV = document.createElement("div"); downloadDIV.style = "cursor:pointer;width:50px;height:40px;line-height:40px;text-align:center;background-color:#FFF;color:#000;position:fixed;top:200px;left:0px;z-index:999;"; downloadDIV.innerText = "下载"; downloadDIV.setAttribute('id','kuaishou-video-downloder'); document.body.appendChild(downloadDIV); downloadDIV.addEventListener("click", function(e){ let videoDom = document.querySelector('.player-video'); if(!videoDom){ console.log('没有找到DOM'); return; } let videoSrc = videoDom.getAttribute('src'); if(videoSrc.match(/^blob/)){ console.log('blob视频无法下载'); return; } commonFunctionObject.GMopenInTab(videoSrc); }); } } document.querySelectorAll(".switch-item").forEach(function(value){ value.addEventListener("click", function(){ downloader(); }); }) downloader(); setInterval(function(){ let kuaishouVideoDownloder = document.querySelector("#kuaishou-video-downloder"); if(kuaishouVideoDownloder){ if(window.location.href.match(/https:\/\/www\.kuaishou\.com\/short-video\/.*?/)){ kuaishouVideoDownloder.style.display = "block"; }else{ kuaishouVideoDownloder.style.display = "none"; } } }, 800); }); }; this.start = function(){ this.douyinVideoDownloader(); this.kuaishouVideoDownloader(); }; }; (new shortVideoDownloader()).start(); })();