您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动下载微信公众号文章视频
// ==UserScript== // @name 自动下载微信公众号文章中的视频 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 自动下载微信公众号文章视频 // @author Zep // @match https://mp.weixin.qq.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=qq.com // @grant GM_log // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_addStyle // @require https://lib.baomitu.com/axios/0.27.2/axios.min.js // @require https://lib.baomitu.com/jquery/1.12.4/jquery.min.js // @license MIT // ==/UserScript== (()=>{ console.log('axios', axios) function downloadVideo1(url) { // 这是传统的下载方式 const downloadFileA = unsafeWindow.document.createElement('a') unsafeWindow.document.body.append(downloadFileA) downloadFileA.href = url // http://mpvideo.qpic.cn/0bc3cyabeaaa2maoapqhensfafwdcilaaeqa.f10002.mp4?dis_k=97a32be63138ce2a2f2bde95e491119e&dis_t=1695370394&play_scene=10120&auth_info=Ws+SvC4/Xkm+rqDbJXVtXXtmQlMRLHRjWHgdFWRDLz5hUEkyPwVVHDgFMjpFNlRSbzA=&auth_key=409cd067a1d042d130c471012ecfb8fa&vid=wxv_2829481345448984576&format_id=10002&support_redirect=0&mmversion=false const filenameArr = url.split('?')[0].split('/') const filename = filenameArr[filenameArr.length - 1] downloadFileA.download = filename downloadFileA.rel = 'noopener noreferrer' // downloadFileA.click() unsafeWindow.document.body.removeChild(downloadFileA) } function downloadVideo2(url) { axios({ method: 'get', url: url, // 必须显式指明响应类型是一个Blob对象,这样生成二进制的数据,才能通过window.URL.createObjectURL进行创建成功 responseType: 'blob', }).then((res) => { if (!res) { return } // 将lob对象转换为域名结合式的url let blobUrl = window.URL.createObjectURL(res.data) let link = document.createElement('a') document.body.appendChild(link) link.style.display = 'none' link.href = blobUrl // 设置a标签的下载属性,设置文件名及格式,后缀名最好让后端在数据格式中返回 const filenameArr = url.split('?')[0].split('/') const filename = filenameArr[filenameArr.length - 1] link.download = filename // 自触发click事件 link.click() document.body.removeChild(link) window.URL.revokeObjectURL(blobUrl); }) } function downloadVideo3(url) { GM_xmlhttpRequest({ url:"url", method :"GET", headers: { // "Content-type": "application/x-www-form-urlencoded", "Host": "mpvideo.qpic.cn", }, responseType: 'blob', onload:function(xhr){ console.log("success", xhr); // 将lob对象转换为域名结合式的url // let blobUrl = window.URL.createObjectURL(xhr.response) var blob = this.response; var reader = new FileReader(); reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href reader.onload = function (e) { let link = document.createElement('a') document.body.appendChild(link) link.style.display = 'none' link.href = e.target.result // 设置a标签的下载属性,设置文件名及格式,后缀名最好让后端在数据格式中返回 const filenameArr = url.split('?')[0].split('/') const filename = filenameArr[filenameArr.length - 1] link.download = filename // 自触发click事件 link.click() document.body.removeChild(link) // window.URL.revokeObjectURL(blobUrl); }; // console.log('blobUrl', blobUrl) } }); } console.log('GM_xmlhttpRequest', GM_xmlhttpRequest) function promise_GM_download(url,i, filename, options = {}){ return new Promise((resolve, reject) => { GM_download({ url: url, name: filename, //不填则自动获取文件名 saveAs: true, //布尔值,显示"保存为"对话框 onerror: function (error) { //如果下载最终出现错误,则要执行的回调 // console.log(`${filename}下载失败,请重试!`,error) reject(error) }, onprogress: (pro) => { //如果此下载取得了一些进展,则要执行的回调 // console.log(pro.loaded) //文件加载量 // console.log(pro.totalSize) //文件总大小 const pecentage = (pro.loaded / pro.totalSize).toFixed(2) * 100 // console.log('.percentage'+ i, 'percentage', pecentage) $('.percentage'+ i).text(pecentage + '%') $('.progress'+ i).val(pecentage) // console.log(`${filename}下载进度:${pecentage}%`) }, ontimeout: () => { //如果此下载由于超时而失败,则要执行的回调 }, onload: () => { //如果此下载完成,则要执行的回调 // console.log(`${filename}下载成功`) resolve(`${filename}下载成功`) }, ...options }) }) } async function downloadVideo4(url,i, filename) { try { const res = await promise_GM_download(url,i, filename,{}) console.log(res) }catch(err) { $('.error'+ i).removeClass('hiddenTip') console.log(err) } /* GM_download({ url: url, name: filename, //不填则自动获取文件名 saveAs: true, //布尔值,显示"保存为"对话框 onerror: function (error) { //如果下载最终出现错误,则要执行的回调 console.log(`${filename}下载失败,请重试!`,error) }, onprogress: (pro) => { //如果此下载取得了一些进展,则要执行的回调 // console.log(pro.loaded) //文件加载量 // console.log(pro.totalSize) //文件总大小 const pecentage = pro.loaded / pro.totalSize * 100 console.log(`${filename}下载进度:${pecentage}%`) }, ontimeout: () => { //如果此下载由于超时而失败,则要执行的回调 }, onload: () => { //如果此下载完成,则要执行的回调 console.log(`${filename}下载成功`) } }) */ } // 往页面上注入弹窗页面 function addPage() { GM_addStyle( ` .myPage { position: fixed; top: 50%; right: 0; padding: 10px; background: #eee; min-height: 500px; width: 500px; box-sizing: border-box; display: flex; flex-direction: column; border: 2px solid deepskyblue; transform: translate(0%, -50%); } .title { color: deepskyblue; font-size: 18px; margin: 10px 0; font-weight: 700; } .list { /* display: flex; flex-direction: column; flex-wrap: wrap; align-items: flex-start; */ overflow-x: auto; height: 400px; } .list-title { font-size: 14px; } .list-item { display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 5px; } .top { width: 100%; display: flex; align-items: flex-start; justify-content: flex-start; } .bottom { width: 100%; display: flex; justify-content: flex-start; } .error { font-size: 12px; color: red; width: 100%; display: flex; justify-content: flex-start; align-items: center; margin: 0 10px; } .hiddenTip { display: none!important; } .error-tip { } .progress { margin: 0 10px; } .retryBtn { padding: 5px; color: #fff; background-color: #409eff; border: none; border-radius: 10%; font-size: 12px; } .line { width: 100%; height: 1px; background-color: #fff; margin: 10px 0; } `) const div = document.createElement('div') div.classList.add('myPage'); div.innerHTML = ` <div class="title">自动下载微信公众号文章中的所有视频</div> <div class="list-title">该页面共存在<span class='count'>10</span>个视频文件:</div> <div class="list"> </div> ` document.body.append(div) } window.onload = function(){ $('body').on('click', '.retryBtn', function(e) { let url = e.target.attributes.getNamedItem('data-src').nodeValue const filename = e.target.attributes.getNamedItem('data-filename').nodeValue const i = e.target.attributes.getNamedItem('data-i').nodeValue // 点击事件处理程序 console.log('点击了动态添加的元素', e, url,filename,i); // url = url.replace('12345', '') $('.error'+ i).addClass('hiddenTip') downloadVideo4(url, i, filename) }) console.log('onload') addPage() const videos = window.document.querySelectorAll('video') $('.count').text(videos.length) for(let i = 0; i < videos.length; i++) { let url = videos[i].getAttribute('src') const filenameArr = url.split('?')[0].split('/') let filename = i+1 + '-' + filenameArr[filenameArr.length - 1] const suffixs = filename.split('.') const suffix = suffixs[suffixs.length - 1] filename = i+1 + '-' + new Date().getTime() + '.' + suffix // if(i === 1) { // url = '12345' + url // } $('.list').append(` <div class="list-item"> <div class="top"> <div>${i+1}.</div> <div>${filename}:</div> </div> <div class="bottom"> <progress class="progress${i+1}" value="0" max="100"></progress> <div class="percentage${i+1}">0%</div> </div> <div class="error hiddenTip error${i+1}"> <div class="error-tip error-tip${i+1}">下载失败,请重试!</div> <button class="retryBtn" data-src=${url} data-i=${i+1} data-filename=${filename}>重试</button> </div> <div class="line"></div> </div> `) downloadVideo4(url, i+1, filename) } } } )()