// ==UserScript== // @name 短视频去水印(支持抖音网页版) // @version 1.2.3 // @license MIT // @description 一款短视频去水印下载工具,支持抖音网页版视频无水印下载 // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAA6aSURBVHja7Jp7dJNlnsd/6+wsMsoC4rQ0SZO8fS9JmuRN3ksSwAFmgDk74uDIIBR03JbawUoLouzMGaEedXDkVlzFKlQZwGJBysXbDtCbvaXpxbaAFZ1x3c16ORzU442meVNp890/0nuLgAzjsbbnfE6bc97f5fnked/3ed6+BIC+z9CogFEBowJGBYwKGBUwKuD7LSAcmNdH7S8pXLeEtPrbKFK/mMKNaaQ1ppPWuHQIOJ1F//mHOXTVjwwkCEIvHMeR3W4nj8dDbrd7hqIor6qq+r6iKEFFUd69AEFVVd+XZflVWZZn+nw+slgsNHnyZDIYDL0QTaBNq2cSzqwYtjetMZ3CTWkUCSyicE0Khetvo68C8+mrugW9XL6AM9m0cfUson/RkSDwxPMxWJYlu91OXq/3UVVVoSjKN0JVVfh8vvWCIFBcXBzpdDrS6XSk1+uIaBytWzmd8NG3KeB0Fj1+/xyiqw1ktVrIYokhCAI5nc6lHo/nGw26/+cpU6bAZrOl63Q6MhqNZDQayWQyEtFEyv3dtz0D3sygz/2p5HBKNNnoII9HIVmWSVGUq1RVfWfwwCRJ2i/LcqqiKJmKomQNIlNRlFRJkl4YRsq7Xq/3Bz6fj6ZNm0JGViZJ9tLn/lTCmxnfngCtYSkhmEm1hSmkMzvJxIrk9aqkxH4GDF5V1e2S20V2h5s4q5sE20A4q5vsTje5XSIpirKtJ1aWZaiqCq/Xq06b6iNGkCgxyU11+xYTgpmkNSz99gSEG5ZSR+NSwsdZ5H9hEelMTjKyIvm86qzB36LXq85PEkTirS6aPdNH06d5BjB7po94q4tYi4t8XvWWwfEejzLHmCSSzugk/75FhI+WU0d3D9/eDBgsYd8i0puclMS7Zk6d4oHHo8LjUTF1igdJgmu+gRGppmAhoTWDPq1JHQBaM6imYCEZGJGSBNctg+NZwfVTval78B9nXWDwly3gNtLql1CkPoXCjalfK6BHQqRxKeGTLKrZu5AmxNnkfxrLY2KcDRPjbKCxPCYl2G8KvBBrHq0ZhDcH0ZpB+DiLAi8sokkJ9rk0lsfEH9swIc6Gq8bymBifrF784PsLWEjhmkWXKmAxafVLrorU3zYr3Lh0mdZ4Z5rWmJ76dYQb0lM7GtNTcWb5vIqilIdvT5mOlZmzsWr5bCz49XQcKlj4GD7NnhtpiB07XHykIT0Vn2bPPVSw8LEFv56OVctnY+Xds3H7oukoO5jyR3ycNa/jPPFDuTMt3JS+LBJImRWuWXRVuH7J+QVogXm9tNfeSOG6JV6tadm7WvMyaE3LoDX99qIIv/5baA0ZwP9lAV+sAj65J8YX9wIfZENryIgdc6H4D7JjMb3xqy4qfii9/b8brlvi+6r2ZjpXf2svvQJCtfMoVDuP2v1zSQvcOiPcfDe05rugNS+H1pIN7filEWnJxlf9ONeSjUjzJcQ3x2L659CaL70PrSUbWstyaC2Z0JrvQkfd4hkR/zzSaueRVntzn4C22puprXYetfl/SVpjepN24h5ETtwLrSkDWuMd0Br//TvKHdCaMmJjOXEPtMY7m0JVN1Jb9Y3UVj23T0Ck/laK1C+gSP2tN4RPrILWvBztVbMQKhERKk5GqNjxHSUZoWIR7VU/g9ayHOHjqxBpSPlJpCGFIg2L+wk4eQdFjqdQpDn9j1pzNkIlItqOmBEqdiJU6kao1PUdxY1QsRNtRxi0l4jQjmeh4/W71kX8v6FIILVPQMcLTuo44KZIS3Z9qGY22o4wCJWpCJVKI4MyNfaFVv4UWsvKho6qm6ij8qZ+M6DISR2vzGTCjUs720rt3fakkUWJG23FNmivp3VG6hcymv8X/e4Cry+k8JsrssN1tyJ0hEWoVL6IpDJCpQrae//+Rw9KvsTaMtqOcNACCxA6kZn9ed0t/S+CC67Rmu7e31YxC2ePWNBWLKOtWBpIiYS20tjvL4tVhMtEoCoBqI4HqowIlSg4WyLHjiuRhsZfLt15z5bICJUoQKURqIoHqhIQLhPxZbE6oMehOWS0HREQqvgZwo1Z+7Xa267peySmLfo5PlnxBU4pwFsu4G1lIH9TgLcUwK8AfhWokxCtSoL/QCb2F2zFWy/9CgiYgTovotUKovUK8I4C/FUZmutS+WssV7ReQbRaAeq8QK0Zp176FfYXbEXtgUxEq5KAOgnwq4jWdPf6t2FyveUGTrmAT1Z8ga/+8PNeAXufnJ+/N+8XKNwodBZudnUUbhYHsHu92HF4i9gRPODsChaJXWcOXN9VXpgZfSS/Cbn5Zch9thrHi2ZHPyzSdX1wWIyeKhQ7CzaIkT2bxCG5LpU9m8SOgg1i5M1CsfPDw2L0wyJ91/GiOdHcZ6uRm1+GdflNKC/MjJ45cH1XsEjsCh5wdh1+LNbz0HyujsINQufevH/D3qcXPNMrgP45IZ/G6EFjedBYrmsAP+K6iLgu3WS+69VNXPSVDUnRgznXRvPzNmFn4VE8v3s78gsrsHNzBg6tHROtzuOiT67iokRcJ/1wUK5vwg+5LiKuc+sqLlqdx0UPrR0T/XPunXim8DU8v3s7dhYeRf6Tm3Aw59roKxuSov+1iYvqJ/NdRN29D8nJg8YYQD+I7xMgCEIGx3HgWHYIPMfiungWbieHI5tZvLyewaGca7Fvx6MoPFiOvYXPo/BwJfZtTUXRmqtR+QSLp1ezmBjPgmHYYXNeCgzDYkI8i6fvY1G1lUXRmjHYtzUVhYcrY7UPlmPfjkdxKOdavLSewbHNLCQnh+viY70PPyYOPM9n9AowGo2z7XbHZ5IkQRTFAbhcIvSMiKk+Ee8dduD0i3Z8UJSAwmfWIjevCNu3PYWNeQdRuut2nCmKw9lSJ1553In4RBF2hzgk36Vid4iIN4h4+XEHzpY6cKYoHqW7foONeQexfdtTyM0rQuEza/FBUQJOv2jH+4cdmOYToTfHeh86HhccDsdnNpttdq8AjuPsLpfrjalTp8Lj8QzA6/WAsXgwY7oHnQ0K0CIDJwVsy12GjBXrkbP2fqQt34CKgvnAGzzwjoLafSr0Zg9kxTMk36UiKx7oTR7496rAfyvAGzwqCuYjbfkG5Ky9Hxkr1mNb7jLgpAC0yOhsUDBzugpGiPU+ON+UKVPgcrlaBUGw9wowmUxxNpvtqM/nG+YprQITr2DGNAXnKiTA7wb8LLZtWYUVv9+CdQ/n4K7VW1G+a3HsTnBCRvUuGQkmBW5J+caPxHtwSwoSTAqqdsrACRkImFG+azHuWv0E1j2cgxW/34LtW1YBfhbwu3GuUsKMG2SY+Fjvg/P5fD7YbLajRqMxrr8AslqtO7xe73kFTJ+m4FylBPhlIGDE7seXYenq55Dz4Eak3rcLgT03ArXMlROwq0cAg8CeuUi9dxdyHtqItPuew+7HlwEBI+CX0XkBAV6vF1ardYfJZOpbCCUkJBDHcTkXLcDvQO3TPB5csxJrH9qCzWsWIbg31gBOSFdQQKz+/+41YtPaFKx9aAseWrMSgW084HcAfvmCM8Dr9YLjuAcSEhL6BJjNZuJ5Pq378fXXC6iRgFofWp5lsD9nIl7dwODAA+Px3sFkRGs8V1xAtMaD9w4l48AD4/HqBgb7cybg+A4GCPiAGulrZ0DP+HieTzObzTTgFGAYZo4syxj835zhBHS8JiNUpqA6T8DLjybi5O5kdFbFdo84eQUFnJQQKpHQWa3ixK5kvPKnRFQ/xSNUriDymgzUSF87AzweD2RZBsMwcwacAiaTicxms02SpAsL8Ev4slhCR6WMrhoF4TIJUb+CcLmEs8euvICzxyS0l8uxmmUSumoURCplfFksXZQASZLAMIxtgAC9Xk8Gg2Gcy+X6bPB1YDgBoe4NR3uZhI4KufdzW8mVF9BTJ1QqIVIho72sb6N2IQFerxcul+szvV4/TqfT9QlgGIbMZjM5nc7WixHQdp4t5z9KwLC1L1KAw+Fo7Z7xAwUYjUYabi0wkgT4fD4kJycfNRqNxDDMUAFWq/XZkT4DrFbrjiECEhMTSafTEcdxD4x0AT1rAIPB0CcgKSmJGIYhjuPSBr+kMFIE9KwBOI5LYxiGkpKShgoYbi0wUgT0XwOYzeaBp0A/AUPWAiNJgCRJMJvNtiECDAYD6fV60ul0Q9YCI0VA/zWAwWCgxMTEgXsBs9lMiYmJ5HA4WvvfCkeKAJ/PB4fD0dpzBxgwA/q/3iYIwrGehwcjRUDPeHieP8YwDLEsSyzLDp0B3Suk/OTkZPh8Pni9Xnj6CeiskoCAhPZyCeHhKJOAVgnVz/2dBRgVVO+WgdZYjeFqt5fHeuus7hPgUWNTv3sBBJPJlB97zc5EA/YC48ePp/Hjx9M111xDBoMh3WKxwGKxIHZBVGEWVMy4QUWnXwYaZJyrPA+vycDbMmr2KNCZVEiy2nv7+aZIsgqdSUXNHgV4O1bjfPXRIKOzVsbMnygwC7F3jCRJgsVigdVqhV6vT7/66qtp3LhxNG7cuD4BDoejF6fTSYIgnGRZFhzHwWa1IE5vhSpZEci3ILBNQMXW4XntCQGnCgQUPGjB9QlW8IIVVuvlwQtWXJ9gRcGDFpwqiNU4X/3ANgF1+RZ4JCvi9FbYrBZwHAeWZSEIwkmbzUZWq7WXXgGSJJEkSSTLMomiSDzPcxaL5SNBEMDzHCZN5iCLPEq2cPjLRhYv/ml4Dj/Cwv8ki+2/4zApnoM5iQPHXR5MEofrJnPY/h8c/E+yOPTI+ev/ZSOLssdivV43mQPPcxAEAVar9SNBEPjk5GQSRZGcTic5nc4+AS6Xi1wuF7nd7p4ZQDabbZwgCI9YrZb/+bFOOK24hGB1nhCs2CoEj20ZnqO5QrBlhxDcuVYITkoQgiwnBAXh8mA5IThpshDcuUYItvxZCB7JPX/9iq1CsOYpIai6heD1OuG01Wp5VxCER5KTk//VYrGQzWYjh8NBdrud7Hb76OvyowJGBYwKGBUwKmBUwKiA77eA/x8Ahqi0JXRn5g8AAAAASUVORK5CYII= // @author 我爱工具箱 // @match *://*.douyin.com/* // @require https://lib.baomitu.com/jquery/3.6.0/jquery.js // @require https://lib.baomitu.com/sweetalert/2.1.2/sweetalert.min.js // @require https://lib.baomitu.com/clipboard.js/2.0.6/clipboard.min.js // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM_openInTab // @grant GM_notification // @grant GM_xmlhttpRequest // @grant GM_download // @grant unsafeWindow // @namespace https://greasyfork.org/users/894875 // ==/UserScript== (function() { let showTipErrorSwal = function(err) { showSwal(err, { icon: 'error' }); } const divTips = document.createElement('div'); divTips.id = "divTips"; let showSwal = function(content, option) { divTips.innerHTML = content; option.content = divTips; if (!option.hasOwnProperty('button')) { option.button = '我知道了' } swal(option); } let headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", "Origin": "https://www.douyin.com", "Referer": "https://www.douyin.com" } let isDouyinPage = function() { let url = location.href; if (url.indexOf(".douyin.com/") != -1) { return true; } else { return false; } }; let getVideoUrl = function() { let RENDER_DATA = document.getElementById("RENDER_DATA"); if (RENDER_DATA == null) { return ""; } let RENDER_DATA_STR = RENDER_DATA.textContent; renderData = decodeURIComponent(RENDER_DATA_STR); let jsonObject = JSON.parse(renderData); let data = null; for (let key in jsonObject) { if ("_location" == key || "app" == key || "11" == key) { continue; } data = key; } let dataJo = jsonObject[data]; let detail = dataJo["videoDetail"]; let video = detail["video"]; let playAddr = video["playAddr"]; let video1 = playAddr[0]; let src = video1["src"]; let videoUrl = "https:" + src; videoUrl = videoUrl.substring(0, videoUrl.length - 1); return videoUrl; } var isDownVideo = false; let successCall = function(videoUrl, videoName) { if (videoUrl == null) { videoUrl = getVideoUrl(); } if (!isDownVideo) { GM_download({ url: videoUrl, name: videoName + '.mp4', headers: headers}); isDownVideo = true; } } let initButtonEvent = function(btn) { if (isDouyinPage()) { var isClickDownVideo = true; let videoType = Number.parseInt(btn.getAttribute("type")); if(videoType == 1) { videoDownloadNum = 0; let videoIndex = btn.getAttribute("videoIndex"); let videoSlide = document.getElementById("slidelist"); let videoClassArr = videoSlide.firstChild.firstChild; //推荐~朋友 let videoArr = videoClassArr.getElementsByClassName("page-recommend-container"); if(videoArr.length == 0) { //首页 videoArr = videoClassArr.getElementsByClassName("dySwiperSlide"); } let videoItemDiv = videoArr[videoIndex]; let account = videoItemDiv.getElementsByClassName("account-name")[0].textContent; let accountNameSpanNode = videoItemDiv.getElementsByClassName("title")[0].childNodes[0]; let title = accountNameSpanNode.firstElementChild.lastElementChild.textContent; let videoName = account + "-" + title; if(videoName == "") { videoName = "无标题视频"; } let sliderVideoDiv = videoItemDiv.getElementsByClassName("slider-video"); let xgVideoContainerDiv = sliderVideoDiv[0].getElementsByClassName("xg-video-container"); let videoNode = xgVideoContainerDiv[0].getElementsByTagName("video"); let videoSrc = videoNode[0].getAttribute("src"); if(videoSrc != null) { // showTipErrorSwal("暂不支持该视频下载,正在加紧适配中..."); const originFetch = fetch; unsafeWindow.fetch = (...arg) => { // console.log('fetch arg', ...arg); if (arg[0].indexOf('douyin') > -1 && isClickDownVideo) { let videoUrl = decodeURI('https:' + arg[0]); GM_xmlhttpRequest(headRequest(videoUrl, videoName, successCall)); if(successCall) { isClickDownVideo = false; } } } }else{ let sourceNodes = videoNode[0].getElementsByTagName("source"); for (let i = 0; i < sourceNodes.length; i++) { try { let videoUrl = decodeURI('https:' + sourceNodes[i].getAttribute("src")); GM_xmlhttpRequest(headRequest(videoUrl, videoName, successCall)); if(successCall) { isDownVideo = false; break; } } catch (error) { console.error(error); } } } }else if(videoType == 2) { let videoClassArr = document.getElementsByClassName("playerControlHeight"); // let videoInfoArr = videoClassArr[0].getElementsByClassName("leftContainer"); // let videoNameArr = videoInfoArr[0].childNodes[2].firstElementChild.getElementsByTagName("h1"); // let title = videoNameArr[0].textContent; let userDiv = videoClassArr[0].childNodes[1].firstElementChild; let accountNameArr = userDiv.childNodes[0].childNodes[1].getElementsByTagName("a")[0].getElementsByTagName("span")[0]; let account = accountNameArr.textContent; let titleArr = userDiv.childNodes[1].getElementsByTagName("span")[0]; let title = titleArr.textContent; let videoName = account + "-" + title; if(videoName == "") { videoName = "无标题视频"; } let videoArr = videoClassArr[0].getElementsByClassName("xg-video-container"); let videoNode = videoArr[0].getElementsByTagName("video"); let sourceNodes = videoNode[0].getElementsByTagName("source"); for (let i = 0; i < sourceNodes.length; i++) { try { let videoUrl = decodeURI('https:' + sourceNodes[i].getAttribute("src")); GM_xmlhttpRequest(headRequest(videoUrl, videoName, successCall)); if(successCall) { isDownVideo = false; break; } } catch (error) { console.error(error); } } }else if(videoType == 3) { let videoDiv= document.getElementById("slideMode"); let account = videoDiv.getElementsByClassName("account-name")[0].textContent; let accountNameSpanNode = videoDiv.getElementsByClassName("title")[0].childNodes[0]; let title = accountNameSpanNode.firstElementChild.lastElementChild.textContent; let videoName = account + "-" + title; if(videoName == "") { videoName = "无标题视频"; } let xgVideoContainerDiv = videoDiv.getElementsByClassName('xg-video-container'); let videoNode = xgVideoContainerDiv[0].getElementsByTagName("video"); let videoSrc = videoNode[0].getAttribute("src"); if(videoSrc != null) { // showTipErrorSwal("暂不支持该视频下载,正在加紧适配中..."); const originFetch = fetch; unsafeWindow.fetch = (...arg) => { // console.log('fetch arg', ...arg); if (arg[0].indexOf('douyin') > -1 && isClickDownVideo) { let videoUrl = decodeURI('https:' + arg[0]); GM_xmlhttpRequest(headRequest(videoUrl, videoName, successCall)); if(successCall) { isClickDownVideo = false; } } } }else{ let sourceNodes = videoNode[0].getElementsByTagName("source"); for (let i = 0; i < sourceNodes.length; i++) { try { let videoUrl = decodeURI('https:' + sourceNodes[i].getAttribute("src")); GM_xmlhttpRequest(headRequest(videoUrl, videoName, successCall)); if(successCall) { isDownVideo = false; break; } } catch (error) { console.error(error); } } } } } }; let headRequest = function(url, videoName, call) { let userAgent = navigator.userAgent; let method = "HEAD"; if(userAgent.indexOf("Firefox") != -1) { method = "GET"; } return { method: method, timeout: 300000, // 30秒超时 headers: headers, url: url, onload: function(res) { if (res.status === 200 || res.status === 401) { call(url, videoName); }else if(res.status === 302) { let Location = res.headers.getAttribute("Location"); call(Location, videoName); }else if(res.status === 403) { showTipErrorSwal("浏览器不支持该视频"); } else { console.error(res); } }, ontimeout: (res) => { console.error(res); }, onerror: (res) => { console.error(res); } } }; let start = function() { if (!isDouyinPage()) { // console.log('非抖音页面,1秒后将重新查找!'); return; } if(document.body.innerHTML == "") { return; } let isIndexVideo = getIndexVideo(); if(!isIndexVideo) { if(!getIndexDetailVideo()) { getDetailVideo(); } } } /** * 首页/推荐/我的 * @returns */ function getIndexVideo() { let videoSlide = document.getElementById("slidelist"); if(videoSlide == null) { // console.log('未查找到视频列表div!'); return false; } let videoClassArr = videoSlide.firstChild.firstChild; if(videoClassArr.length == 0) { // console.log('未查找到视频div!'); return false; } //推荐~朋友 let videoArr = videoClassArr.getElementsByClassName("page-recommend-container"); if(videoArr.length == 0) { //首页 videoArr = videoClassArr.getElementsByClassName("dySwiperSlide"); } if(videoArr.length == 0) { // console.log('未查找到视频div列表'); return false; } //偏移量 let shiftingDiv = videoSlide.getElementsByClassName("fullscreen_capture_feedback"); let height = shiftingDiv[0].style.height; let shifting = 0; if(height != "100%") { shifting = height.match(/calc\(\d+%\s*-\s*(\d+)px\)/i)[1]; } //每个视频的高度 let firstVideoDiv = videoArr[0]; let firstVideoHeight = firstVideoDiv.style.height; firstVideoHeight = firstVideoHeight.replace("px", ""); let videoTransForm= videoClassArr.style.transform || ''; //视频下标 var videoIndex = 0; let videoTransFormarr = videoTransForm.match(/translate3d\(\d+px,\s*(-+\d+)px,\s*(\d+)px\)/i); if(videoTransFormarr != null) { let videoTransFormY = videoTransFormarr[1]; videoTransFormY = -videoTransFormY; videoIndex = videoTransFormY/(parseInt(firstVideoHeight) + parseInt(shifting)); } let btnBox = videoArr[videoIndex].getElementsByClassName('positionBox'); if(btnBox.length == 0) { // console.log('可能为直播页面或登录弹出页面'); return false; } if(btnBox[0].childNodes.length > 1) { var btnShare = btnBox[0].childNodes[1]; }else{ var btnShare = btnBox[0].childNodes[0]; } if(btnShare == undefined) { // console.log('可能还未初始化分享按钮'); return false; } let btnDownload = { class: 'btnClickDownload', title: '点击下载视频', html: function() { return ``; } } //如果是已有下载按钮,则不添加 let buttonArr = btnShare.getElementsByClassName(btnDownload.class); if (buttonArr.length != 0) { return false; } let btn = document.createElement('a'); btn.setAttribute("type", 1); btn.setAttribute("class", btnDownload.class); btn.setAttribute("videoIndex", videoIndex); btn.title = btnDownload.title; btn.innerHTML = btnDownload.html(); btn.addEventListener('click', function(e) { initButtonEvent(btn); e.preventDefault(); }); btnShare.appendChild(btn); return true; } /** * 首页/推荐/我的-详情 * @returns */ function getIndexDetailVideo() { let videoDiv= document.getElementById("slideMode"); if(videoDiv == null) { // console.log('未查找到视频div!'); return false; } let positionBoxDiv = videoDiv.getElementsByClassName("positionBox"); let btnShare = positionBoxDiv[0].childNodes[1]; if(btnShare == undefined) { // console.log('可能还未初始化分享按钮'); return false; } let btnDownload = { class: 'btnClickDownload', title: '点击下载视频', html: function() { return ``; } } //如果是已有下载按钮,则不添加 let buttonArr = btnShare.getElementsByClassName(btnDownload.class); if (buttonArr.length != 0) { return false; } let btn = document.createElement('a'); btn.setAttribute("type", 3); btn.setAttribute("class", btnDownload.class); btn.title = btnDownload.title; btn.innerHTML = btnDownload.html(); btn.addEventListener('click', function(e) { initButtonEvent(btn); e.preventDefault(); }); btnShare.appendChild(btn); return true; } /** * 进入详情页详情 * @returns */ function getDetailVideo() { let videoClassArr = document.getElementsByClassName("playerControlHeight"); if(videoClassArr.length == 0) { // console.log('未查找到视频总div!'); return false; } let videoDiv = videoClassArr[0]; //详情 let videoArr = videoDiv.getElementsByClassName("xg-video-container"); if(videoArr.length == 0) { // console.log('未查找到视频div'); return false; } let btnGrid = videoDiv.getElementsByClassName('xg-right-grid'); let btnDownload = { class: 'btnClickDownload', title: '点击下载视频', html: function() { return ``; } } //如果是已有下载按钮,则不添加 let buttonArr = btnGrid[0].getElementsByClassName(btnDownload.class); if (buttonArr.length != 0) { return false; } let btn = document.createElement('a'); btn.setAttribute("type", 2); btn.setAttribute("class", btnDownload.class); btn.title = btnDownload.title; btn.innerHTML = btnDownload.html(); btn.addEventListener('click', function(e) { initButtonEvent(btn); e.preventDefault(); }); btnGrid[0].appendChild(btn); return true; } setInterval(function() { start(); }, 1000) })();