From 7bfd55a79363a4f5f03b6aaf6f5ebb79983a5c71 Mon Sep 17 00:00:00 2001 From: the1812 Date: Wed, 6 Nov 2019 23:02:42 +0800 Subject: [PATCH] Add types for batch download --- bilibili-evolved.offline.user.js | 6 +- bilibili-evolved.preview-offline.user.js | 6 +- bilibili-evolved.preview.user.js | 4 +- bilibili-evolved.user.js | 4 +- min/batch-download.min.js | 2 +- min/bundle.json | 4 +- min/bundle.zip | Bin 1431278 -> 1431214 bytes min/download-video.min.js | 2 +- src/video/download-video/batch-download.d.ts | 13 --- .../{batch-download.js => batch-download.ts} | 80 ++++++++++-------- src/video/download-video/download-video.ts | 6 +- 11 files changed, 61 insertions(+), 66 deletions(-) delete mode 100644 src/video/download-video/batch-download.d.ts rename src/video/download-video/{batch-download.js => batch-download.ts} (77%) diff --git a/bilibili-evolved.offline.user.js b/bilibili-evolved.offline.user.js index e825984ba..5df790e52 100644 --- a/bilibili-evolved.offline.user.js +++ b/bilibili-evolved.offline.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name Bilibili Evolved (Offline) -// @version 478.20 +// @version 478.30 // @description Bilibili Evolved 的离线版, 所有功能都已内置于脚本中. // @author Grant Howard, Coulomb-G // @copyright 2019, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G) @@ -1051,7 +1051,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-continue.min.js"] = (()=>{return(e,i)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}function t(i){const t=i.text();if(/第(\d+)话/.test(t)){if(e.allowJumpContinue){i.parent().find(".bilibili-player-video-toast-item-jump").click()}return}const n=/((\d)*:)?(\d)*:(\d)*/g;const r=t.match(n);if(!r){return}const o=r[0].split(":");const l=(()=>{if(o.length===3){const[e,i,t]=o.map(e=>parseInt(e));return e*60*60+i*60+t}else if(o.length===2){const[e,i]=o.map(e=>parseInt(e));return e*60+i}else{logError(`解析历史时间发生错误: historyTime=${JSON.stringify(o)}`);return NaN}})();const s=i.parent();const a=document.querySelector("video");if(l从头开始`);e.appendTo(s).on("click",()=>{a.currentTime=0;s.find(".bilibili-player-video-toast-item-close").get(0).click()});i.html(`已跳转到上次历史记录${r[0]}`)}else{s.find(".bilibili-player-video-toast-item-close").get(0).click()}}function n(){SpinQuery.condition(()=>$(".bilibili-player-video-toast-item-text"),e=>e.text().indexOf("上次看到")!==-1,e=>t(e.filter((e,i)=>i.innerText.indexOf("上次看到")!==-1)))}Observer.videoChange(n)}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-draw.min.js"] = (()=>{return(t,n)=>{(async()=>{if(!/^https:\/\/live\.bilibili\.com\/[\d]+/.test(document.URL)){return}const t=await SpinQuery.condition(()=>dq(".chat-popups-section"),t=>t.querySelector("chat-draw-area")===null);if(!t){console.warn("[自动领奖] 未能找到弹窗容器");return}Observer.childListSubtree(t,()=>{let t;console.log("draw button = ",dq(".chat-popups-section .draw>span:nth-child(3)"));t=dq(".chat-popups-section .draw>span:nth-child(3)");if(t===null){const t=dq(".chat-popups-section .function-bar>span:nth-child(3)");if(t!==null){const n=Observer.attributes(t,()=>{if(t.style.display!=="none"){n.forEach(t=>t.stop());t.click()}})}}if(t!==null){t.click()}})})()}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-play.min.js"] = (()=>{return(e,d)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}SpinQuery.condition(()=>document.querySelector(".bilibili-player-video video"),e=>e&&e.paused===true,e=>e.play())}})(); -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return[]}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return[]}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return[]}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/biliplus-redirect.min.js"] = (()=>{return(i,e)=>{const n=`hd.biliplus.com`;const c=["bilibili.com/video/av","bilibili.com/bangumi/play","bilibili.com/bangumi/media","space.bilibili.com"];return{widget:{condition:()=>{return c.some(i=>document.URL.includes(i))},content:`\n`,success:()=>{const i=document.querySelector("#biliplus-redirect");i.addEventListener("click",()=>{if(location.host==="space.bilibili.com"){location.assign(document.URL.replace("space.bilibili.com/",`${n}/space/`))}else if(document.URL.includes("/bangumi/")){const i=unsafeWindow.aid||document.querySelector(".av-link,.info-sec-av").innerText.replace(/[aAvV]/g,"");location.assign(`https://${n}/video/av${i}/`)}else{location.host=n}})}}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.min.js"] = (()=>{return(e,t)=>{const r=async()=>{if(dq(".international-home")){const e=await SpinQuery.condition(()=>unsafeWindow["__INITIAL_STATE__"],e=>e!==undefined);return dqa(".home-slide .item").slice(0,5).map((t,r)=>{const i=t.querySelector("a").getAttribute("data-loc-id");return{url:e.locsData[i][r].url,title:t.querySelector(".title").innerText.trim(),isAd:Boolean(t.querySelector(".gg-icon")),imageUrl:t.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}else{const e=dq(".chief-recommend-module .panel");const t=e.querySelector(".pic");const r=e.querySelectorAll(".title > a");return[...t.querySelectorAll("li")].map((e,t)=>{const i=r[t];return{url:i.getAttribute("href"),title:i.innerText.trim(),isAd:Boolean(i.querySelector(".gg-pic")),imageUrl:e.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}};return{export:{getBlackboards:r}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.vue.min.js"] = (()=>{return(a,r)=>{const i=``;r.applyStyleFromText(`.simple-home .blackboards{display:grid;grid-template-areas:"header header" "dots cards";grid-template-columns:8px 1fr;grid-template-rows:1fr 250px;row-gap:16px;column-gap:16px;align-self:start}.simple-home .blackboards .blackboard-cards{grid-area:cards;--blackboard-width:500px;--blackboard-height:250px;width:var(--blackboard-width);height:var(--blackboard-height);border-radius:16px;overflow:hidden}.simple-home .blackboards .blackboard-cards .blackboard-card{width:100%;height:100%;position:relative;display:block;transition:.3s cubic-bezier(.65,.05,.36,1)}.simple-home .blackboards .blackboard-cards .blackboard-card img{width:100%;height:100%;object-fit:fill;display:block}.simple-home .blackboards .blackboard-cards .blackboard-card .title{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);padding:4px 16px;color:#fff;background-color:#000a;font-size:14px;font-weight:700;border-radius:14px;white-space:nowrap;opacity:0}.simple-home .blackboards .blackboard-cards .blackboard-card:hover .title{opacity:1}`,"blackboard-style");return{export:Object.assign({template:i},{components:{Icon:()=>r.importAsync("icon.vue"),"dpi-img":()=>r.importAsync("dpi-img.vue")},data(){return{blackboards:[],interval:0}},destroyed(){if(this.interval){clearInterval(this.interval)}},computed:{cardsContainer(){return this.$el.querySelector(".blackboard-cards")}},async mounted(){const{getBlackboards:a}=await r.importAsync("blackboard");this.blackboards=(await a()).filter(a=>!a.isAd);const i=dq(".blackboards");this.interval=setInterval(()=>{if(!document.hasFocus()||i.matches(".blackboards:hover")){return}const a=parseInt(dq(`.blackboard-radio:checked`).getAttribute("data-index"));let r;if(a===this.blackboards.length-1){r=0}else{r=a+1}dq(`.blackboard-radio[data-index='${r}']`).checked=true},5e3)}})}}})(); @@ -1088,7 +1088,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video-package.min.js"] = (()=>{return(e,t)=>{class n{constructor(e={}){this.config=e;this.entries=[]}download(e,t){const i=document.createElement("a");const s=URL.createObjectURL(t);if(n.lastPackageUrl){URL.revokeObjectURL(n.lastPackageUrl)}n.lastPackageUrl=s;i.setAttribute("href",s);i.setAttribute("download",e);document.body.appendChild(i);i.click();i.remove()}add(e,t){if(t===null||t===undefined){return}this.entries.push({name:e,data:t})}async preEmit(){const e=this.entries.filter(e=>[".flv",".mp4",".m4s"].some(t=>e.name.endsWith(t)));if(this.config.ffmpeg!==undefined&&e.length>=2){if(this.config.ffmpeg==="文件列表"||this.config.ffmpeg==="文件列表+脚本"){this.entries.push({name:"ffmpeg-files.txt",data:e.map(e=>`file '${e.name}'`).join("\n")})}if(this.config.ffmpeg==="文件列表+脚本"){const e=`ffmpeg -f concat -i ffmpeg-files.txt -c copy ""`;this.entries.push({name:"ffmpeg.bat",data:e},{name:"ffmpeg.sh",data:e.replace(/"/g,"'")})}}}async blob(){await this.preEmit();if(this.entries.length===0){return null}if(this.entries.length===1){const e=this.entries[0].data;return typeof e==="string"?new Blob([e]):e}const e=new JSZip;this.entries.forEach(({name:t,data:n})=>{e.file(t,n)});return await e.generateAsync({type:"blob"})}async emit(e){if(this.entries.length===0){return}if(!e||this.entries.length===1){e=this.entries[0].name}const t=await this.blob();if(!t){return}return this.download(e,t)}static async single(e,t,i={}){const s=new n(i);s.add(e,t);return await s.emit()}}n.lastPackageUrl="";return{export:{DownloadVideoPackage:n}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.css"] = `.download-video{--download-video-background:white;--download-video-foreground:black;position:absolute;top:96px;left:50%;transform:translateX(-50%) scale(.95);background:var(--download-video-background);color:var(--download-video-foreground);box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;z-index:10001;pointer-events:none;opacity:0;padding:16px;width:300px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.download-video,.download-video *{transition:.2s ease-out;-webkit-tap-highlight-color:transparent!important}.download-video.opened{pointer-events:initial;opacity:1;transform:translateX(-50%) scale(1)}body.dark .download-video{--download-video-background:#222;--download-video-foreground:#eee}.round-corner .download-video,.round-corner .download-video .episode-list .v-checkbox,.round-corner .download-video .rpc-settings{border-radius:var(--large-corner-radius)}.round-corner .download-video .button,.round-corner .download-video .cover,.round-corner .download-video .direct-download .progress .background,.round-corner .download-video .direct-download .progress .foreground,.round-corner .download-video .rpc-settings input[type=text],.round-corner .download-video .title,.round-corner .download-video button{border-radius:var(--corner-radius)}.download-video .cover{min-height:100px;max-height:120px;object-fit:contain}.download-video h1{font-size:13pt;font-weight:700;color:var(--download-video-foreground)}.download-video h2{font-size:11pt;font-weight:700;color:var(--download-video-foreground)}.download-video .header{display:flex;justify-content:space-between;align-items:center}.download-video .header .grow{flex-grow:1}.download-video .header .mdi-download{font-size:16pt;color:var(--download-video-foreground);margin-right:8px}.download-video .header .mdi-close{font-size:16pt;color:var(--download-video-foreground);cursor:pointer}.download-video .header .mdi-close:hover{color:var(--theme-color)}.download-video .info{display:flex;flex-direction:column;align-items:center;margin-top:12px}.download-video .title{display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;margin-top:12px}.download-video .title .bold{width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.download-video .title .size{font-size:10pt;color:var(--download-video-foreground);align-self:center;display:flex;align-items:center;height:24px}.download-video .bold{color:var(--download-video-foreground);font-weight:700;font-size:12pt}.download-video .option-item{display:flex;justify-content:space-between;align-items:center;padding-top:12px;font-size:10pt}.download-video .tabs{display:flex;padding:12px 0;font-size:10pt}.download-video .tabs .tab{cursor:pointer;position:relative;opacity:.5}.download-video .tabs .tab.active{font-weight:700;opacity:1}.download-video .tabs .tab:not(:last-child){margin-right:16px}.download-video .tabs .tab::after{content:"";position:absolute;border-radius:2px;background-color:var(--theme-color);height:3px;width:80%;left:10%;bottom:-8px;transition:.2s ease-out;transform:scaleX(0)}.download-video .tabs .tab.active::after{transform:scaleX(1)}.download-video .separator{height:1px;background:#8884;width:100%;margin:12px 0;flex-shrink:0}.download-video .direct-download{display:flex;flex-direction:column;align-items:start;justify-content:space-between}.download-video .button,.download-video button{border:none;outline:0!important;padding:6px 16px;font-size:10pt;cursor:pointer;background:#8884;color:var(--download-video-foreground)}.download-video .button:hover,.download-video button:hover{background:#8886}.download-video .primary{background:var(--theme-color);color:var(--foreground-color);align-self:center}.download-video .primary:hover{background:var(--theme-color-90)}.download-video .busy .button,.download-video .busy .primary,.download-video .busy button,.download-video button:disabled{background-color:#0001;color:#8884;cursor:not-allowed}.download-video .busy .button,.download-video .busy button{cursor:wait!important}.download-video .direct-download .progress{align-self:stretch;display:flex;align-items:center;margin-top:8px}.download-video .direct-download .progress .background{flex-grow:1;height:4px;background:#8884;margin-right:4px;position:relative}.download-video .direct-download .progress .background .foreground{position:absolute;top:0;left:0;height:4px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-60))}.download-video .direct-download .progress .percent{width:50px;text-align:right}.download-video .actions{display:flex;flex-wrap:wrap;justify-content:space-between;margin:8px -4px 0}.download-video .actions>*{margin:4px;flex-grow:1;flex-basis:calc(50% - 16px);display:flex;justify-content:center;align-items:center}.download-video i.mdi-alert-circle{font-size:14pt;color:#ff9800}.download-video .size-warning{position:relative;padding:0 8px}.download-video .size-warning-tip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:var(--download-video-background);color:var(--download-video-foreground);border:1px dashed var(--theme-color);z-index:2;font-size:10pt;width:200px;padding:8px;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;pointer-events:none;opacity:0}.download-video .size-warning:hover .size-warning-tip{opacity:1}.download-video .episode-list .v-checkbox{padding:4px 8px;margin:4px 0;position:relative;background-color:transparent}.download-video .episode-list .v-checkbox.checked{background-color:#8882}.download-video .episode-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.download-video .episode-list{overflow:auto;max-height:320px}.download-video button.list-tool{padding:4px;line-height:1;font-size:12pt;margin:0 4px}.download-video .episode-header h2{flex-grow:1}.download-video .selected-count{width:64px;text-align:right}.download-video .aria2-rpc .mdi{margin-left:8px;font-size:14pt;line-height:1}.download-video .aria2-rpc{position:relative}.download-video .rpc-settings{position:absolute;display:flex;flex-direction:column;align-items:stretch;color:var(--download-video-foreground);background:#fff;bottom:120%;left:50%;cursor:initial;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;transform-origin:bottom;transform:translateX(-50%) scale(.9);opacity:0;pointer-events:none;padding:8px;z-index:3;transition:.3s cubic-bezier(.18,.89,.32,1.28);width:120%}body.dark .download-video .rpc-settings{background:#282828}.download-video .rpc-settings>*{margin:8px}.download-video .rpc-settings.show{opacity:1;transform:translateX(-50%) scale(1);pointer-events:initial}.download-video .rpc-settings input[type=text]{background:0 0;color:var(--download-video-foreground);border:1px solid #8884;padding:4px;margin-left:8px}.download-video .rpc-settings input[type=text]:focus{border-color:var(--theme-color)}.download-video .rpc-settings .operations{display:flex;align-items:center;justify-content:space-evenly}.download-video .final-dir{word-break:break-all}.download-video .rpc-settings-item{display:flex;align-items:center;justify-content:space-between;white-space:nowrap}.download-video .rpc-settings-item input[type=text]{flex-grow:1;margin-left:24px}.download-video button.cancel-download,.download-video button.start-download{margin-top:8px}.download-video .direct-download-header{align-self:stretch;display:flex;justify-content:space-between;align-items:center}body.dark .download-video .direct-download .progress .foreground{background:linear-gradient(to right,var(--theme-color-70),var(--theme-color))}`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.html"] = `

下载视频

单个视频
批量导出
警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.
预计大小: {{displaySize}}
格式
清晰度
弹幕
首选编码
ffmpeg支持

直接下载

{{speed}}
{{progressPercent}}%

选集

{{selectedEpisodeCount}}/{{episodeList.length}}

导出

{{showRpcSettings ? '取消' : 'aria2 RPC'}}

aria2 RPC

配置

主机
端口
密钥
限速
默认路径
路径
最终路径: {{rpcSettings.baseDir + rpcSettings.dir}}
方法
开始下载
{{saveRpcSettingsText}}
`; -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}this.batchExtractor=new s;this.batch=true;this.episodeList=(await this.batchExtractor.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}const a=this.batchExtractor=new s;this.batch=true;this.episodeList=(await a.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/dpi-img.vue.min.js"] = (()=>{return(t,s)=>{const e=``;return{export:Object.assign({template:e},{props:["size","src","blur","root","rootMargin","threshold"],data(){return{srcset:null,actualSrc:null}},methods:{calcSrc(){if(!this.src||!this.size){return null}const t=this.src.substring(this.src.lastIndexOf(".")+1);this.srcset=getDpiSourceSet(this.src,this.size,t);this.actualSrc=this.src}},mounted(){const t={root:this.root,rootMargin:this.rootMargin||"200px",threshold:this.threshold};const s=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){this.calcSrc();s.disconnect()}})},t);s.observe(this.$el)},computed:{width(){if(typeof this.size==="object"&&"width"in this.size){return this.size.width}return null},height(){if(typeof this.size==="object"&&"height"in this.size){return this.size.height}return null}}})}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-danmaku.min.js"] = (()=>{return(e,a)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}Observer.videoChange(async()=>{const e=await SpinQuery.select(".bui-collapse-wrap");if(e&&e.classList.contains("bui-collapse-wrap-folded")){const e=await SpinQuery.select(".bui-collapse-header");e.click()}})}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-description.min.css"] = `.play-up-info .play-up-self,.video-desc .info{height:auto!important}.play-up-info .play-up-self-btn,.video-desc .btn{display:none!important}`; diff --git a/bilibili-evolved.preview-offline.user.js b/bilibili-evolved.preview-offline.user.js index 101153af3..3da2f6db0 100644 --- a/bilibili-evolved.preview-offline.user.js +++ b/bilibili-evolved.preview-offline.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name Bilibili Evolved (Preview Offline) -// @version 478.20 +// @version 478.30 // @description Bilibili Evolved 的预览离线版, 可以抢先体验新功能, 并且所有功能都已内置于脚本中. // @author Grant Howard, Coulomb-G // @copyright 2019, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G) @@ -1051,7 +1051,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-continue.min.js"] = (()=>{return(e,i)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}function t(i){const t=i.text();if(/第(\d+)话/.test(t)){if(e.allowJumpContinue){i.parent().find(".bilibili-player-video-toast-item-jump").click()}return}const n=/((\d)*:)?(\d)*:(\d)*/g;const r=t.match(n);if(!r){return}const o=r[0].split(":");const l=(()=>{if(o.length===3){const[e,i,t]=o.map(e=>parseInt(e));return e*60*60+i*60+t}else if(o.length===2){const[e,i]=o.map(e=>parseInt(e));return e*60+i}else{logError(`解析历史时间发生错误: historyTime=${JSON.stringify(o)}`);return NaN}})();const s=i.parent();const a=document.querySelector("video");if(l从头开始`);e.appendTo(s).on("click",()=>{a.currentTime=0;s.find(".bilibili-player-video-toast-item-close").get(0).click()});i.html(`已跳转到上次历史记录${r[0]}`)}else{s.find(".bilibili-player-video-toast-item-close").get(0).click()}}function n(){SpinQuery.condition(()=>$(".bilibili-player-video-toast-item-text"),e=>e.text().indexOf("上次看到")!==-1,e=>t(e.filter((e,i)=>i.innerText.indexOf("上次看到")!==-1)))}Observer.videoChange(n)}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-draw.min.js"] = (()=>{return(t,n)=>{(async()=>{if(!/^https:\/\/live\.bilibili\.com\/[\d]+/.test(document.URL)){return}const t=await SpinQuery.condition(()=>dq(".chat-popups-section"),t=>t.querySelector("chat-draw-area")===null);if(!t){console.warn("[自动领奖] 未能找到弹窗容器");return}Observer.childListSubtree(t,()=>{let t;console.log("draw button = ",dq(".chat-popups-section .draw>span:nth-child(3)"));t=dq(".chat-popups-section .draw>span:nth-child(3)");if(t===null){const t=dq(".chat-popups-section .function-bar>span:nth-child(3)");if(t!==null){const n=Observer.attributes(t,()=>{if(t.style.display!=="none"){n.forEach(t=>t.stop());t.click()}})}}if(t!==null){t.click()}})})()}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-play.min.js"] = (()=>{return(e,d)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}SpinQuery.condition(()=>document.querySelector(".bilibili-player-video video"),e=>e&&e.paused===true,e=>e.play())}})(); -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return[]}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return[]}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return[]}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/biliplus-redirect.min.js"] = (()=>{return(i,e)=>{const n=`hd.biliplus.com`;const c=["bilibili.com/video/av","bilibili.com/bangumi/play","bilibili.com/bangumi/media","space.bilibili.com"];return{widget:{condition:()=>{return c.some(i=>document.URL.includes(i))},content:`\n`,success:()=>{const i=document.querySelector("#biliplus-redirect");i.addEventListener("click",()=>{if(location.host==="space.bilibili.com"){location.assign(document.URL.replace("space.bilibili.com/",`${n}/space/`))}else if(document.URL.includes("/bangumi/")){const i=unsafeWindow.aid||document.querySelector(".av-link,.info-sec-av").innerText.replace(/[aAvV]/g,"");location.assign(`https://${n}/video/av${i}/`)}else{location.host=n}})}}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.min.js"] = (()=>{return(e,t)=>{const r=async()=>{if(dq(".international-home")){const e=await SpinQuery.condition(()=>unsafeWindow["__INITIAL_STATE__"],e=>e!==undefined);return dqa(".home-slide .item").slice(0,5).map((t,r)=>{const i=t.querySelector("a").getAttribute("data-loc-id");return{url:e.locsData[i][r].url,title:t.querySelector(".title").innerText.trim(),isAd:Boolean(t.querySelector(".gg-icon")),imageUrl:t.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}else{const e=dq(".chief-recommend-module .panel");const t=e.querySelector(".pic");const r=e.querySelectorAll(".title > a");return[...t.querySelectorAll("li")].map((e,t)=>{const i=r[t];return{url:i.getAttribute("href"),title:i.innerText.trim(),isAd:Boolean(i.querySelector(".gg-pic")),imageUrl:e.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}};return{export:{getBlackboards:r}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.vue.min.js"] = (()=>{return(a,r)=>{const i=``;r.applyStyleFromText(`.simple-home .blackboards{display:grid;grid-template-areas:"header header" "dots cards";grid-template-columns:8px 1fr;grid-template-rows:1fr 250px;row-gap:16px;column-gap:16px;align-self:start}.simple-home .blackboards .blackboard-cards{grid-area:cards;--blackboard-width:500px;--blackboard-height:250px;width:var(--blackboard-width);height:var(--blackboard-height);border-radius:16px;overflow:hidden}.simple-home .blackboards .blackboard-cards .blackboard-card{width:100%;height:100%;position:relative;display:block;transition:.3s cubic-bezier(.65,.05,.36,1)}.simple-home .blackboards .blackboard-cards .blackboard-card img{width:100%;height:100%;object-fit:fill;display:block}.simple-home .blackboards .blackboard-cards .blackboard-card .title{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);padding:4px 16px;color:#fff;background-color:#000a;font-size:14px;font-weight:700;border-radius:14px;white-space:nowrap;opacity:0}.simple-home .blackboards .blackboard-cards .blackboard-card:hover .title{opacity:1}`,"blackboard-style");return{export:Object.assign({template:i},{components:{Icon:()=>r.importAsync("icon.vue"),"dpi-img":()=>r.importAsync("dpi-img.vue")},data(){return{blackboards:[],interval:0}},destroyed(){if(this.interval){clearInterval(this.interval)}},computed:{cardsContainer(){return this.$el.querySelector(".blackboard-cards")}},async mounted(){const{getBlackboards:a}=await r.importAsync("blackboard");this.blackboards=(await a()).filter(a=>!a.isAd);const i=dq(".blackboards");this.interval=setInterval(()=>{if(!document.hasFocus()||i.matches(".blackboards:hover")){return}const a=parseInt(dq(`.blackboard-radio:checked`).getAttribute("data-index"));let r;if(a===this.blackboards.length-1){r=0}else{r=a+1}dq(`.blackboard-radio[data-index='${r}']`).checked=true},5e3)}})}}})(); @@ -1088,7 +1088,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video-package.min.js"] = (()=>{return(e,t)=>{class n{constructor(e={}){this.config=e;this.entries=[]}download(e,t){const i=document.createElement("a");const s=URL.createObjectURL(t);if(n.lastPackageUrl){URL.revokeObjectURL(n.lastPackageUrl)}n.lastPackageUrl=s;i.setAttribute("href",s);i.setAttribute("download",e);document.body.appendChild(i);i.click();i.remove()}add(e,t){if(t===null||t===undefined){return}this.entries.push({name:e,data:t})}async preEmit(){const e=this.entries.filter(e=>[".flv",".mp4",".m4s"].some(t=>e.name.endsWith(t)));if(this.config.ffmpeg!==undefined&&e.length>=2){if(this.config.ffmpeg==="文件列表"||this.config.ffmpeg==="文件列表+脚本"){this.entries.push({name:"ffmpeg-files.txt",data:e.map(e=>`file '${e.name}'`).join("\n")})}if(this.config.ffmpeg==="文件列表+脚本"){const e=`ffmpeg -f concat -i ffmpeg-files.txt -c copy ""`;this.entries.push({name:"ffmpeg.bat",data:e},{name:"ffmpeg.sh",data:e.replace(/"/g,"'")})}}}async blob(){await this.preEmit();if(this.entries.length===0){return null}if(this.entries.length===1){const e=this.entries[0].data;return typeof e==="string"?new Blob([e]):e}const e=new JSZip;this.entries.forEach(({name:t,data:n})=>{e.file(t,n)});return await e.generateAsync({type:"blob"})}async emit(e){if(this.entries.length===0){return}if(!e||this.entries.length===1){e=this.entries[0].name}const t=await this.blob();if(!t){return}return this.download(e,t)}static async single(e,t,i={}){const s=new n(i);s.add(e,t);return await s.emit()}}n.lastPackageUrl="";return{export:{DownloadVideoPackage:n}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.css"] = `.download-video{--download-video-background:white;--download-video-foreground:black;position:absolute;top:96px;left:50%;transform:translateX(-50%) scale(.95);background:var(--download-video-background);color:var(--download-video-foreground);box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;z-index:10001;pointer-events:none;opacity:0;padding:16px;width:300px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.download-video,.download-video *{transition:.2s ease-out;-webkit-tap-highlight-color:transparent!important}.download-video.opened{pointer-events:initial;opacity:1;transform:translateX(-50%) scale(1)}body.dark .download-video{--download-video-background:#222;--download-video-foreground:#eee}.round-corner .download-video,.round-corner .download-video .episode-list .v-checkbox,.round-corner .download-video .rpc-settings{border-radius:var(--large-corner-radius)}.round-corner .download-video .button,.round-corner .download-video .cover,.round-corner .download-video .direct-download .progress .background,.round-corner .download-video .direct-download .progress .foreground,.round-corner .download-video .rpc-settings input[type=text],.round-corner .download-video .title,.round-corner .download-video button{border-radius:var(--corner-radius)}.download-video .cover{min-height:100px;max-height:120px;object-fit:contain}.download-video h1{font-size:13pt;font-weight:700;color:var(--download-video-foreground)}.download-video h2{font-size:11pt;font-weight:700;color:var(--download-video-foreground)}.download-video .header{display:flex;justify-content:space-between;align-items:center}.download-video .header .grow{flex-grow:1}.download-video .header .mdi-download{font-size:16pt;color:var(--download-video-foreground);margin-right:8px}.download-video .header .mdi-close{font-size:16pt;color:var(--download-video-foreground);cursor:pointer}.download-video .header .mdi-close:hover{color:var(--theme-color)}.download-video .info{display:flex;flex-direction:column;align-items:center;margin-top:12px}.download-video .title{display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;margin-top:12px}.download-video .title .bold{width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.download-video .title .size{font-size:10pt;color:var(--download-video-foreground);align-self:center;display:flex;align-items:center;height:24px}.download-video .bold{color:var(--download-video-foreground);font-weight:700;font-size:12pt}.download-video .option-item{display:flex;justify-content:space-between;align-items:center;padding-top:12px;font-size:10pt}.download-video .tabs{display:flex;padding:12px 0;font-size:10pt}.download-video .tabs .tab{cursor:pointer;position:relative;opacity:.5}.download-video .tabs .tab.active{font-weight:700;opacity:1}.download-video .tabs .tab:not(:last-child){margin-right:16px}.download-video .tabs .tab::after{content:"";position:absolute;border-radius:2px;background-color:var(--theme-color);height:3px;width:80%;left:10%;bottom:-8px;transition:.2s ease-out;transform:scaleX(0)}.download-video .tabs .tab.active::after{transform:scaleX(1)}.download-video .separator{height:1px;background:#8884;width:100%;margin:12px 0;flex-shrink:0}.download-video .direct-download{display:flex;flex-direction:column;align-items:start;justify-content:space-between}.download-video .button,.download-video button{border:none;outline:0!important;padding:6px 16px;font-size:10pt;cursor:pointer;background:#8884;color:var(--download-video-foreground)}.download-video .button:hover,.download-video button:hover{background:#8886}.download-video .primary{background:var(--theme-color);color:var(--foreground-color);align-self:center}.download-video .primary:hover{background:var(--theme-color-90)}.download-video .busy .button,.download-video .busy .primary,.download-video .busy button,.download-video button:disabled{background-color:#0001;color:#8884;cursor:not-allowed}.download-video .busy .button,.download-video .busy button{cursor:wait!important}.download-video .direct-download .progress{align-self:stretch;display:flex;align-items:center;margin-top:8px}.download-video .direct-download .progress .background{flex-grow:1;height:4px;background:#8884;margin-right:4px;position:relative}.download-video .direct-download .progress .background .foreground{position:absolute;top:0;left:0;height:4px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-60))}.download-video .direct-download .progress .percent{width:50px;text-align:right}.download-video .actions{display:flex;flex-wrap:wrap;justify-content:space-between;margin:8px -4px 0}.download-video .actions>*{margin:4px;flex-grow:1;flex-basis:calc(50% - 16px);display:flex;justify-content:center;align-items:center}.download-video i.mdi-alert-circle{font-size:14pt;color:#ff9800}.download-video .size-warning{position:relative;padding:0 8px}.download-video .size-warning-tip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:var(--download-video-background);color:var(--download-video-foreground);border:1px dashed var(--theme-color);z-index:2;font-size:10pt;width:200px;padding:8px;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;pointer-events:none;opacity:0}.download-video .size-warning:hover .size-warning-tip{opacity:1}.download-video .episode-list .v-checkbox{padding:4px 8px;margin:4px 0;position:relative;background-color:transparent}.download-video .episode-list .v-checkbox.checked{background-color:#8882}.download-video .episode-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.download-video .episode-list{overflow:auto;max-height:320px}.download-video button.list-tool{padding:4px;line-height:1;font-size:12pt;margin:0 4px}.download-video .episode-header h2{flex-grow:1}.download-video .selected-count{width:64px;text-align:right}.download-video .aria2-rpc .mdi{margin-left:8px;font-size:14pt;line-height:1}.download-video .aria2-rpc{position:relative}.download-video .rpc-settings{position:absolute;display:flex;flex-direction:column;align-items:stretch;color:var(--download-video-foreground);background:#fff;bottom:120%;left:50%;cursor:initial;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;transform-origin:bottom;transform:translateX(-50%) scale(.9);opacity:0;pointer-events:none;padding:8px;z-index:3;transition:.3s cubic-bezier(.18,.89,.32,1.28);width:120%}body.dark .download-video .rpc-settings{background:#282828}.download-video .rpc-settings>*{margin:8px}.download-video .rpc-settings.show{opacity:1;transform:translateX(-50%) scale(1);pointer-events:initial}.download-video .rpc-settings input[type=text]{background:0 0;color:var(--download-video-foreground);border:1px solid #8884;padding:4px;margin-left:8px}.download-video .rpc-settings input[type=text]:focus{border-color:var(--theme-color)}.download-video .rpc-settings .operations{display:flex;align-items:center;justify-content:space-evenly}.download-video .final-dir{word-break:break-all}.download-video .rpc-settings-item{display:flex;align-items:center;justify-content:space-between;white-space:nowrap}.download-video .rpc-settings-item input[type=text]{flex-grow:1;margin-left:24px}.download-video button.cancel-download,.download-video button.start-download{margin-top:8px}.download-video .direct-download-header{align-self:stretch;display:flex;justify-content:space-between;align-items:center}body.dark .download-video .direct-download .progress .foreground{background:linear-gradient(to right,var(--theme-color-70),var(--theme-color))}`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.html"] = `

下载视频

单个视频
批量导出
警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.
预计大小: {{displaySize}}
格式
清晰度
弹幕
首选编码
ffmpeg支持

直接下载

{{speed}}
{{progressPercent}}%

选集

{{selectedEpisodeCount}}/{{episodeList.length}}

导出

{{showRpcSettings ? '取消' : 'aria2 RPC'}}

aria2 RPC

配置

主机
端口
密钥
限速
默认路径
路径
最终路径: {{rpcSettings.baseDir + rpcSettings.dir}}
方法
开始下载
{{saveRpcSettingsText}}
`; -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}this.batchExtractor=new s;this.batch=true;this.episodeList=(await this.batchExtractor.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}const a=this.batchExtractor=new s;this.batch=true;this.episodeList=(await a.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/dpi-img.vue.min.js"] = (()=>{return(t,s)=>{const e=``;return{export:Object.assign({template:e},{props:["size","src","blur","root","rootMargin","threshold"],data(){return{srcset:null,actualSrc:null}},methods:{calcSrc(){if(!this.src||!this.size){return null}const t=this.src.substring(this.src.lastIndexOf(".")+1);this.srcset=getDpiSourceSet(this.src,this.size,t);this.actualSrc=this.src}},mounted(){const t={root:this.root,rootMargin:this.rootMargin||"200px",threshold:this.threshold};const s=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){this.calcSrc();s.disconnect()}})},t);s.observe(this.$el)},computed:{width(){if(typeof this.size==="object"&&"width"in this.size){return this.size.width}return null},height(){if(typeof this.size==="object"&&"height"in this.size){return this.size.height}return null}}})}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-danmaku.min.js"] = (()=>{return(e,a)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}Observer.videoChange(async()=>{const e=await SpinQuery.select(".bui-collapse-wrap");if(e&&e.classList.contains("bui-collapse-wrap-folded")){const e=await SpinQuery.select(".bui-collapse-header");e.click()}})}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-description.min.css"] = `.play-up-info .play-up-self,.video-desc .info{height:auto!important}.play-up-info .play-up-self-btn,.video-desc .btn{display:none!important}`; diff --git a/bilibili-evolved.preview.user.js b/bilibili-evolved.preview.user.js index 41aba84f9..ae98ad22a 100644 --- a/bilibili-evolved.preview.user.js +++ b/bilibili-evolved.preview.user.js @@ -1050,7 +1050,7 @@ onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/m onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-continue.min.js"] = (()=>{return(e,i)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}function t(i){const t=i.text();if(/第(\d+)话/.test(t)){if(e.allowJumpContinue){i.parent().find(".bilibili-player-video-toast-item-jump").click()}return}const n=/((\d)*:)?(\d)*:(\d)*/g;const r=t.match(n);if(!r){return}const o=r[0].split(":");const l=(()=>{if(o.length===3){const[e,i,t]=o.map(e=>parseInt(e));return e*60*60+i*60+t}else if(o.length===2){const[e,i]=o.map(e=>parseInt(e));return e*60+i}else{logError(`解析历史时间发生错误: historyTime=${JSON.stringify(o)}`);return NaN}})();const s=i.parent();const a=document.querySelector("video");if(l从头开始`);e.appendTo(s).on("click",()=>{a.currentTime=0;s.find(".bilibili-player-video-toast-item-close").get(0).click()});i.html(`已跳转到上次历史记录${r[0]}`)}else{s.find(".bilibili-player-video-toast-item-close").get(0).click()}}function n(){SpinQuery.condition(()=>$(".bilibili-player-video-toast-item-text"),e=>e.text().indexOf("上次看到")!==-1,e=>t(e.filter((e,i)=>i.innerText.indexOf("上次看到")!==-1)))}Observer.videoChange(n)}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-draw.min.js"] = (()=>{return(t,n)=>{(async()=>{if(!/^https:\/\/live\.bilibili\.com\/[\d]+/.test(document.URL)){return}const t=await SpinQuery.condition(()=>dq(".chat-popups-section"),t=>t.querySelector("chat-draw-area")===null);if(!t){console.warn("[自动领奖] 未能找到弹窗容器");return}Observer.childListSubtree(t,()=>{let t;console.log("draw button = ",dq(".chat-popups-section .draw>span:nth-child(3)"));t=dq(".chat-popups-section .draw>span:nth-child(3)");if(t===null){const t=dq(".chat-popups-section .function-bar>span:nth-child(3)");if(t!==null){const n=Observer.attributes(t,()=>{if(t.style.display!=="none"){n.forEach(t=>t.stop());t.click()}})}}if(t!==null){t.click()}})})()}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-play.min.js"] = (()=>{return(e,d)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}SpinQuery.condition(()=>document.querySelector(".bilibili-player-video video"),e=>e&&e.paused===true,e=>e.play())}})(); -onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); +onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return[]}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return[]}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return[]}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/biliplus-redirect.min.js"] = (()=>{return(i,e)=>{const n=`hd.biliplus.com`;const c=["bilibili.com/video/av","bilibili.com/bangumi/play","bilibili.com/bangumi/media","space.bilibili.com"];return{widget:{condition:()=>{return c.some(i=>document.URL.includes(i))},content:`\n`,success:()=>{const i=document.querySelector("#biliplus-redirect");i.addEventListener("click",()=>{if(location.host==="space.bilibili.com"){location.assign(document.URL.replace("space.bilibili.com/",`${n}/space/`))}else if(document.URL.includes("/bangumi/")){const i=unsafeWindow.aid||document.querySelector(".av-link,.info-sec-av").innerText.replace(/[aAvV]/g,"");location.assign(`https://${n}/video/av${i}/`)}else{location.host=n}})}}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/blackboard.min.js"] = (()=>{return(e,t)=>{const r=async()=>{if(dq(".international-home")){const e=await SpinQuery.condition(()=>unsafeWindow["__INITIAL_STATE__"],e=>e!==undefined);return dqa(".home-slide .item").slice(0,5).map((t,r)=>{const i=t.querySelector("a").getAttribute("data-loc-id");return{url:e.locsData[i][r].url,title:t.querySelector(".title").innerText.trim(),isAd:Boolean(t.querySelector(".gg-icon")),imageUrl:t.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}else{const e=dq(".chief-recommend-module .panel");const t=e.querySelector(".pic");const r=e.querySelectorAll(".title > a");return[...t.querySelectorAll("li")].map((e,t)=>{const i=r[t];return{url:i.getAttribute("href"),title:i.innerText.trim(),isAd:Boolean(i.querySelector(".gg-pic")),imageUrl:e.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}};return{export:{getBlackboards:r}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/blackboard.vue.min.js"] = (()=>{return(a,r)=>{const i=``;r.applyStyleFromText(`.simple-home .blackboards{display:grid;grid-template-areas:"header header" "dots cards";grid-template-columns:8px 1fr;grid-template-rows:1fr 250px;row-gap:16px;column-gap:16px;align-self:start}.simple-home .blackboards .blackboard-cards{grid-area:cards;--blackboard-width:500px;--blackboard-height:250px;width:var(--blackboard-width);height:var(--blackboard-height);border-radius:16px;overflow:hidden}.simple-home .blackboards .blackboard-cards .blackboard-card{width:100%;height:100%;position:relative;display:block;transition:.3s cubic-bezier(.65,.05,.36,1)}.simple-home .blackboards .blackboard-cards .blackboard-card img{width:100%;height:100%;object-fit:fill;display:block}.simple-home .blackboards .blackboard-cards .blackboard-card .title{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);padding:4px 16px;color:#fff;background-color:#000a;font-size:14px;font-weight:700;border-radius:14px;white-space:nowrap;opacity:0}.simple-home .blackboards .blackboard-cards .blackboard-card:hover .title{opacity:1}`,"blackboard-style");return{export:Object.assign({template:i},{components:{Icon:()=>r.importAsync("icon.vue"),"dpi-img":()=>r.importAsync("dpi-img.vue")},data(){return{blackboards:[],interval:0}},destroyed(){if(this.interval){clearInterval(this.interval)}},computed:{cardsContainer(){return this.$el.querySelector(".blackboard-cards")}},async mounted(){const{getBlackboards:a}=await r.importAsync("blackboard");this.blackboards=(await a()).filter(a=>!a.isAd);const i=dq(".blackboards");this.interval=setInterval(()=>{if(!document.hasFocus()||i.matches(".blackboards:hover")){return}const a=parseInt(dq(`.blackboard-radio:checked`).getAttribute("data-index"));let r;if(a===this.blackboards.length-1){r=0}else{r=a+1}dq(`.blackboard-radio[data-index='${r}']`).checked=true},5e3)}})}}})(); @@ -1087,7 +1087,7 @@ onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/m onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/download-video-package.min.js"] = (()=>{return(e,t)=>{class n{constructor(e={}){this.config=e;this.entries=[]}download(e,t){const i=document.createElement("a");const s=URL.createObjectURL(t);if(n.lastPackageUrl){URL.revokeObjectURL(n.lastPackageUrl)}n.lastPackageUrl=s;i.setAttribute("href",s);i.setAttribute("download",e);document.body.appendChild(i);i.click();i.remove()}add(e,t){if(t===null||t===undefined){return}this.entries.push({name:e,data:t})}async preEmit(){const e=this.entries.filter(e=>[".flv",".mp4",".m4s"].some(t=>e.name.endsWith(t)));if(this.config.ffmpeg!==undefined&&e.length>=2){if(this.config.ffmpeg==="文件列表"||this.config.ffmpeg==="文件列表+脚本"){this.entries.push({name:"ffmpeg-files.txt",data:e.map(e=>`file '${e.name}'`).join("\n")})}if(this.config.ffmpeg==="文件列表+脚本"){const e=`ffmpeg -f concat -i ffmpeg-files.txt -c copy ""`;this.entries.push({name:"ffmpeg.bat",data:e},{name:"ffmpeg.sh",data:e.replace(/"/g,"'")})}}}async blob(){await this.preEmit();if(this.entries.length===0){return null}if(this.entries.length===1){const e=this.entries[0].data;return typeof e==="string"?new Blob([e]):e}const e=new JSZip;this.entries.forEach(({name:t,data:n})=>{e.file(t,n)});return await e.generateAsync({type:"blob"})}async emit(e){if(this.entries.length===0){return}if(!e||this.entries.length===1){e=this.entries[0].name}const t=await this.blob();if(!t){return}return this.download(e,t)}static async single(e,t,i={}){const s=new n(i);s.add(e,t);return await s.emit()}}n.lastPackageUrl="";return{export:{DownloadVideoPackage:n}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/download-video.min.css"] = `.download-video{--download-video-background:white;--download-video-foreground:black;position:absolute;top:96px;left:50%;transform:translateX(-50%) scale(.95);background:var(--download-video-background);color:var(--download-video-foreground);box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;z-index:10001;pointer-events:none;opacity:0;padding:16px;width:300px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.download-video,.download-video *{transition:.2s ease-out;-webkit-tap-highlight-color:transparent!important}.download-video.opened{pointer-events:initial;opacity:1;transform:translateX(-50%) scale(1)}body.dark .download-video{--download-video-background:#222;--download-video-foreground:#eee}.round-corner .download-video,.round-corner .download-video .episode-list .v-checkbox,.round-corner .download-video .rpc-settings{border-radius:var(--large-corner-radius)}.round-corner .download-video .button,.round-corner .download-video .cover,.round-corner .download-video .direct-download .progress .background,.round-corner .download-video .direct-download .progress .foreground,.round-corner .download-video .rpc-settings input[type=text],.round-corner .download-video .title,.round-corner .download-video button{border-radius:var(--corner-radius)}.download-video .cover{min-height:100px;max-height:120px;object-fit:contain}.download-video h1{font-size:13pt;font-weight:700;color:var(--download-video-foreground)}.download-video h2{font-size:11pt;font-weight:700;color:var(--download-video-foreground)}.download-video .header{display:flex;justify-content:space-between;align-items:center}.download-video .header .grow{flex-grow:1}.download-video .header .mdi-download{font-size:16pt;color:var(--download-video-foreground);margin-right:8px}.download-video .header .mdi-close{font-size:16pt;color:var(--download-video-foreground);cursor:pointer}.download-video .header .mdi-close:hover{color:var(--theme-color)}.download-video .info{display:flex;flex-direction:column;align-items:center;margin-top:12px}.download-video .title{display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;margin-top:12px}.download-video .title .bold{width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.download-video .title .size{font-size:10pt;color:var(--download-video-foreground);align-self:center;display:flex;align-items:center;height:24px}.download-video .bold{color:var(--download-video-foreground);font-weight:700;font-size:12pt}.download-video .option-item{display:flex;justify-content:space-between;align-items:center;padding-top:12px;font-size:10pt}.download-video .tabs{display:flex;padding:12px 0;font-size:10pt}.download-video .tabs .tab{cursor:pointer;position:relative;opacity:.5}.download-video .tabs .tab.active{font-weight:700;opacity:1}.download-video .tabs .tab:not(:last-child){margin-right:16px}.download-video .tabs .tab::after{content:"";position:absolute;border-radius:2px;background-color:var(--theme-color);height:3px;width:80%;left:10%;bottom:-8px;transition:.2s ease-out;transform:scaleX(0)}.download-video .tabs .tab.active::after{transform:scaleX(1)}.download-video .separator{height:1px;background:#8884;width:100%;margin:12px 0;flex-shrink:0}.download-video .direct-download{display:flex;flex-direction:column;align-items:start;justify-content:space-between}.download-video .button,.download-video button{border:none;outline:0!important;padding:6px 16px;font-size:10pt;cursor:pointer;background:#8884;color:var(--download-video-foreground)}.download-video .button:hover,.download-video button:hover{background:#8886}.download-video .primary{background:var(--theme-color);color:var(--foreground-color);align-self:center}.download-video .primary:hover{background:var(--theme-color-90)}.download-video .busy .button,.download-video .busy .primary,.download-video .busy button,.download-video button:disabled{background-color:#0001;color:#8884;cursor:not-allowed}.download-video .busy .button,.download-video .busy button{cursor:wait!important}.download-video .direct-download .progress{align-self:stretch;display:flex;align-items:center;margin-top:8px}.download-video .direct-download .progress .background{flex-grow:1;height:4px;background:#8884;margin-right:4px;position:relative}.download-video .direct-download .progress .background .foreground{position:absolute;top:0;left:0;height:4px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-60))}.download-video .direct-download .progress .percent{width:50px;text-align:right}.download-video .actions{display:flex;flex-wrap:wrap;justify-content:space-between;margin:8px -4px 0}.download-video .actions>*{margin:4px;flex-grow:1;flex-basis:calc(50% - 16px);display:flex;justify-content:center;align-items:center}.download-video i.mdi-alert-circle{font-size:14pt;color:#ff9800}.download-video .size-warning{position:relative;padding:0 8px}.download-video .size-warning-tip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:var(--download-video-background);color:var(--download-video-foreground);border:1px dashed var(--theme-color);z-index:2;font-size:10pt;width:200px;padding:8px;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;pointer-events:none;opacity:0}.download-video .size-warning:hover .size-warning-tip{opacity:1}.download-video .episode-list .v-checkbox{padding:4px 8px;margin:4px 0;position:relative;background-color:transparent}.download-video .episode-list .v-checkbox.checked{background-color:#8882}.download-video .episode-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.download-video .episode-list{overflow:auto;max-height:320px}.download-video button.list-tool{padding:4px;line-height:1;font-size:12pt;margin:0 4px}.download-video .episode-header h2{flex-grow:1}.download-video .selected-count{width:64px;text-align:right}.download-video .aria2-rpc .mdi{margin-left:8px;font-size:14pt;line-height:1}.download-video .aria2-rpc{position:relative}.download-video .rpc-settings{position:absolute;display:flex;flex-direction:column;align-items:stretch;color:var(--download-video-foreground);background:#fff;bottom:120%;left:50%;cursor:initial;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;transform-origin:bottom;transform:translateX(-50%) scale(.9);opacity:0;pointer-events:none;padding:8px;z-index:3;transition:.3s cubic-bezier(.18,.89,.32,1.28);width:120%}body.dark .download-video .rpc-settings{background:#282828}.download-video .rpc-settings>*{margin:8px}.download-video .rpc-settings.show{opacity:1;transform:translateX(-50%) scale(1);pointer-events:initial}.download-video .rpc-settings input[type=text]{background:0 0;color:var(--download-video-foreground);border:1px solid #8884;padding:4px;margin-left:8px}.download-video .rpc-settings input[type=text]:focus{border-color:var(--theme-color)}.download-video .rpc-settings .operations{display:flex;align-items:center;justify-content:space-evenly}.download-video .final-dir{word-break:break-all}.download-video .rpc-settings-item{display:flex;align-items:center;justify-content:space-between;white-space:nowrap}.download-video .rpc-settings-item input[type=text]{flex-grow:1;margin-left:24px}.download-video button.cancel-download,.download-video button.start-download{margin-top:8px}.download-video .direct-download-header{align-self:stretch;display:flex;justify-content:space-between;align-items:center}body.dark .download-video .direct-download .progress .foreground{background:linear-gradient(to right,var(--theme-color-70),var(--theme-color))}`; onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/download-video.min.html"] = `

下载视频

单个视频
批量导出
警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.
预计大小: {{displaySize}}
格式
清晰度
弹幕
首选编码
ffmpeg支持

直接下载

{{speed}}
{{progressPercent}}%

选集

{{selectedEpisodeCount}}/{{episodeList.length}}

导出

{{showRpcSettings ? '取消' : 'aria2 RPC'}}

aria2 RPC

配置

主机
端口
密钥
限速
默认路径
路径
最终路径: {{rpcSettings.baseDir + rpcSettings.dir}}
方法
开始下载
{{saveRpcSettingsText}}
`; -onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}this.batchExtractor=new s;this.batch=true;this.episodeList=(await this.batchExtractor.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); +onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}const a=this.batchExtractor=new s;this.batch=true;this.episodeList=(await a.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/dpi-img.vue.min.js"] = (()=>{return(t,s)=>{const e=``;return{export:Object.assign({template:e},{props:["size","src","blur","root","rootMargin","threshold"],data(){return{srcset:null,actualSrc:null}},methods:{calcSrc(){if(!this.src||!this.size){return null}const t=this.src.substring(this.src.lastIndexOf(".")+1);this.srcset=getDpiSourceSet(this.src,this.size,t);this.actualSrc=this.src}},mounted(){const t={root:this.root,rootMargin:this.rootMargin||"200px",threshold:this.threshold};const s=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){this.calcSrc();s.disconnect()}})},t);s.observe(this.$el)},computed:{width(){if(typeof this.size==="object"&&"width"in this.size){return this.size.width}return null},height(){if(typeof this.size==="object"&&"height"in this.size){return this.size.height}return null}}})}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/expand-danmaku.min.js"] = (()=>{return(e,a)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}Observer.videoChange(async()=>{const e=await SpinQuery.select(".bui-collapse-wrap");if(e&&e.classList.contains("bui-collapse-wrap-folded")){const e=await SpinQuery.select(".bui-collapse-header");e.click()}})}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/expand-description.min.css"] = `.play-up-info .play-up-self,.video-desc .info{height:auto!important}.play-up-info .play-up-self-btn,.video-desc .btn{display:none!important}`; diff --git a/bilibili-evolved.user.js b/bilibili-evolved.user.js index 87d7348b0..06557d100 100644 --- a/bilibili-evolved.user.js +++ b/bilibili-evolved.user.js @@ -1050,7 +1050,7 @@ onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/mi onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-continue.min.js"] = (()=>{return(e,i)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}function t(i){const t=i.text();if(/第(\d+)话/.test(t)){if(e.allowJumpContinue){i.parent().find(".bilibili-player-video-toast-item-jump").click()}return}const n=/((\d)*:)?(\d)*:(\d)*/g;const r=t.match(n);if(!r){return}const o=r[0].split(":");const l=(()=>{if(o.length===3){const[e,i,t]=o.map(e=>parseInt(e));return e*60*60+i*60+t}else if(o.length===2){const[e,i]=o.map(e=>parseInt(e));return e*60+i}else{logError(`解析历史时间发生错误: historyTime=${JSON.stringify(o)}`);return NaN}})();const s=i.parent();const a=document.querySelector("video");if(l从头开始`);e.appendTo(s).on("click",()=>{a.currentTime=0;s.find(".bilibili-player-video-toast-item-close").get(0).click()});i.html(`已跳转到上次历史记录${r[0]}`)}else{s.find(".bilibili-player-video-toast-item-close").get(0).click()}}function n(){SpinQuery.condition(()=>$(".bilibili-player-video-toast-item-text"),e=>e.text().indexOf("上次看到")!==-1,e=>t(e.filter((e,i)=>i.innerText.indexOf("上次看到")!==-1)))}Observer.videoChange(n)}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-draw.min.js"] = (()=>{return(t,n)=>{(async()=>{if(!/^https:\/\/live\.bilibili\.com\/[\d]+/.test(document.URL)){return}const t=await SpinQuery.condition(()=>dq(".chat-popups-section"),t=>t.querySelector("chat-draw-area")===null);if(!t){console.warn("[自动领奖] 未能找到弹窗容器");return}Observer.childListSubtree(t,()=>{let t;console.log("draw button = ",dq(".chat-popups-section .draw>span:nth-child(3)"));t=dq(".chat-popups-section .draw>span:nth-child(3)");if(t===null){const t=dq(".chat-popups-section .function-bar>span:nth-child(3)");if(t!==null){const n=Observer.attributes(t,()=>{if(t.style.display!=="none"){n.forEach(t=>t.stop());t.click()}})}}if(t!==null){t.click()}})})()}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/auto-play.min.js"] = (()=>{return(e,d)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}SpinQuery.condition(()=>document.querySelector(".bilibili-player-video video"),e=>e&&e.paused===true,e=>e.play())}})(); -onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); +onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return[]}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return[]}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return[]}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/biliplus-redirect.min.js"] = (()=>{return(i,e)=>{const n=`hd.biliplus.com`;const c=["bilibili.com/video/av","bilibili.com/bangumi/play","bilibili.com/bangumi/media","space.bilibili.com"];return{widget:{condition:()=>{return c.some(i=>document.URL.includes(i))},content:`\n`,success:()=>{const i=document.querySelector("#biliplus-redirect");i.addEventListener("click",()=>{if(location.host==="space.bilibili.com"){location.assign(document.URL.replace("space.bilibili.com/",`${n}/space/`))}else if(document.URL.includes("/bangumi/")){const i=unsafeWindow.aid||document.querySelector(".av-link,.info-sec-av").innerText.replace(/[aAvV]/g,"");location.assign(`https://${n}/video/av${i}/`)}else{location.host=n}})}}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.min.js"] = (()=>{return(e,t)=>{const r=async()=>{if(dq(".international-home")){const e=await SpinQuery.condition(()=>unsafeWindow["__INITIAL_STATE__"],e=>e!==undefined);return dqa(".home-slide .item").slice(0,5).map((t,r)=>{const i=t.querySelector("a").getAttribute("data-loc-id");return{url:e.locsData[i][r].url,title:t.querySelector(".title").innerText.trim(),isAd:Boolean(t.querySelector(".gg-icon")),imageUrl:t.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}else{const e=dq(".chief-recommend-module .panel");const t=e.querySelector(".pic");const r=e.querySelectorAll(".title > a");return[...t.querySelectorAll("li")].map((e,t)=>{const i=r[t];return{url:i.getAttribute("href"),title:i.innerText.trim(),isAd:Boolean(i.querySelector(".gg-pic")),imageUrl:e.querySelector("img").getAttribute("src").replace(/@.+$/,"")}})}};return{export:{getBlackboards:r}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/blackboard.vue.min.js"] = (()=>{return(a,r)=>{const i=``;r.applyStyleFromText(`.simple-home .blackboards{display:grid;grid-template-areas:"header header" "dots cards";grid-template-columns:8px 1fr;grid-template-rows:1fr 250px;row-gap:16px;column-gap:16px;align-self:start}.simple-home .blackboards .blackboard-cards{grid-area:cards;--blackboard-width:500px;--blackboard-height:250px;width:var(--blackboard-width);height:var(--blackboard-height);border-radius:16px;overflow:hidden}.simple-home .blackboards .blackboard-cards .blackboard-card{width:100%;height:100%;position:relative;display:block;transition:.3s cubic-bezier(.65,.05,.36,1)}.simple-home .blackboards .blackboard-cards .blackboard-card img{width:100%;height:100%;object-fit:fill;display:block}.simple-home .blackboards .blackboard-cards .blackboard-card .title{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);padding:4px 16px;color:#fff;background-color:#000a;font-size:14px;font-weight:700;border-radius:14px;white-space:nowrap;opacity:0}.simple-home .blackboards .blackboard-cards .blackboard-card:hover .title{opacity:1}`,"blackboard-style");return{export:Object.assign({template:i},{components:{Icon:()=>r.importAsync("icon.vue"),"dpi-img":()=>r.importAsync("dpi-img.vue")},data(){return{blackboards:[],interval:0}},destroyed(){if(this.interval){clearInterval(this.interval)}},computed:{cardsContainer(){return this.$el.querySelector(".blackboard-cards")}},async mounted(){const{getBlackboards:a}=await r.importAsync("blackboard");this.blackboards=(await a()).filter(a=>!a.isAd);const i=dq(".blackboards");this.interval=setInterval(()=>{if(!document.hasFocus()||i.matches(".blackboards:hover")){return}const a=parseInt(dq(`.blackboard-radio:checked`).getAttribute("data-index"));let r;if(a===this.blackboards.length-1){r=0}else{r=a+1}dq(`.blackboard-radio[data-index='${r}']`).checked=true},5e3)}})}}})(); @@ -1087,7 +1087,7 @@ onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/mi onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video-package.min.js"] = (()=>{return(e,t)=>{class n{constructor(e={}){this.config=e;this.entries=[]}download(e,t){const i=document.createElement("a");const s=URL.createObjectURL(t);if(n.lastPackageUrl){URL.revokeObjectURL(n.lastPackageUrl)}n.lastPackageUrl=s;i.setAttribute("href",s);i.setAttribute("download",e);document.body.appendChild(i);i.click();i.remove()}add(e,t){if(t===null||t===undefined){return}this.entries.push({name:e,data:t})}async preEmit(){const e=this.entries.filter(e=>[".flv",".mp4",".m4s"].some(t=>e.name.endsWith(t)));if(this.config.ffmpeg!==undefined&&e.length>=2){if(this.config.ffmpeg==="文件列表"||this.config.ffmpeg==="文件列表+脚本"){this.entries.push({name:"ffmpeg-files.txt",data:e.map(e=>`file '${e.name}'`).join("\n")})}if(this.config.ffmpeg==="文件列表+脚本"){const e=`ffmpeg -f concat -i ffmpeg-files.txt -c copy ""`;this.entries.push({name:"ffmpeg.bat",data:e},{name:"ffmpeg.sh",data:e.replace(/"/g,"'")})}}}async blob(){await this.preEmit();if(this.entries.length===0){return null}if(this.entries.length===1){const e=this.entries[0].data;return typeof e==="string"?new Blob([e]):e}const e=new JSZip;this.entries.forEach(({name:t,data:n})=>{e.file(t,n)});return await e.generateAsync({type:"blob"})}async emit(e){if(this.entries.length===0){return}if(!e||this.entries.length===1){e=this.entries[0].name}const t=await this.blob();if(!t){return}return this.download(e,t)}static async single(e,t,i={}){const s=new n(i);s.add(e,t);return await s.emit()}}n.lastPackageUrl="";return{export:{DownloadVideoPackage:n}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.css"] = `.download-video{--download-video-background:white;--download-video-foreground:black;position:absolute;top:96px;left:50%;transform:translateX(-50%) scale(.95);background:var(--download-video-background);color:var(--download-video-foreground);box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;z-index:10001;pointer-events:none;opacity:0;padding:16px;width:300px;display:flex;flex-direction:column;align-items:stretch;justify-content:space-between}.download-video,.download-video *{transition:.2s ease-out;-webkit-tap-highlight-color:transparent!important}.download-video.opened{pointer-events:initial;opacity:1;transform:translateX(-50%) scale(1)}body.dark .download-video{--download-video-background:#222;--download-video-foreground:#eee}.round-corner .download-video,.round-corner .download-video .episode-list .v-checkbox,.round-corner .download-video .rpc-settings{border-radius:var(--large-corner-radius)}.round-corner .download-video .button,.round-corner .download-video .cover,.round-corner .download-video .direct-download .progress .background,.round-corner .download-video .direct-download .progress .foreground,.round-corner .download-video .rpc-settings input[type=text],.round-corner .download-video .title,.round-corner .download-video button{border-radius:var(--corner-radius)}.download-video .cover{min-height:100px;max-height:120px;object-fit:contain}.download-video h1{font-size:13pt;font-weight:700;color:var(--download-video-foreground)}.download-video h2{font-size:11pt;font-weight:700;color:var(--download-video-foreground)}.download-video .header{display:flex;justify-content:space-between;align-items:center}.download-video .header .grow{flex-grow:1}.download-video .header .mdi-download{font-size:16pt;color:var(--download-video-foreground);margin-right:8px}.download-video .header .mdi-close{font-size:16pt;color:var(--download-video-foreground);cursor:pointer}.download-video .header .mdi-close:hover{color:var(--theme-color)}.download-video .info{display:flex;flex-direction:column;align-items:center;margin-top:12px}.download-video .title{display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;margin-top:12px}.download-video .title .bold{width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.download-video .title .size{font-size:10pt;color:var(--download-video-foreground);align-self:center;display:flex;align-items:center;height:24px}.download-video .bold{color:var(--download-video-foreground);font-weight:700;font-size:12pt}.download-video .option-item{display:flex;justify-content:space-between;align-items:center;padding-top:12px;font-size:10pt}.download-video .tabs{display:flex;padding:12px 0;font-size:10pt}.download-video .tabs .tab{cursor:pointer;position:relative;opacity:.5}.download-video .tabs .tab.active{font-weight:700;opacity:1}.download-video .tabs .tab:not(:last-child){margin-right:16px}.download-video .tabs .tab::after{content:"";position:absolute;border-radius:2px;background-color:var(--theme-color);height:3px;width:80%;left:10%;bottom:-8px;transition:.2s ease-out;transform:scaleX(0)}.download-video .tabs .tab.active::after{transform:scaleX(1)}.download-video .separator{height:1px;background:#8884;width:100%;margin:12px 0;flex-shrink:0}.download-video .direct-download{display:flex;flex-direction:column;align-items:start;justify-content:space-between}.download-video .button,.download-video button{border:none;outline:0!important;padding:6px 16px;font-size:10pt;cursor:pointer;background:#8884;color:var(--download-video-foreground)}.download-video .button:hover,.download-video button:hover{background:#8886}.download-video .primary{background:var(--theme-color);color:var(--foreground-color);align-self:center}.download-video .primary:hover{background:var(--theme-color-90)}.download-video .busy .button,.download-video .busy .primary,.download-video .busy button,.download-video button:disabled{background-color:#0001;color:#8884;cursor:not-allowed}.download-video .busy .button,.download-video .busy button{cursor:wait!important}.download-video .direct-download .progress{align-self:stretch;display:flex;align-items:center;margin-top:8px}.download-video .direct-download .progress .background{flex-grow:1;height:4px;background:#8884;margin-right:4px;position:relative}.download-video .direct-download .progress .background .foreground{position:absolute;top:0;left:0;height:4px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-60))}.download-video .direct-download .progress .percent{width:50px;text-align:right}.download-video .actions{display:flex;flex-wrap:wrap;justify-content:space-between;margin:8px -4px 0}.download-video .actions>*{margin:4px;flex-grow:1;flex-basis:calc(50% - 16px);display:flex;justify-content:center;align-items:center}.download-video i.mdi-alert-circle{font-size:14pt;color:#ff9800}.download-video .size-warning{position:relative;padding:0 8px}.download-video .size-warning-tip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:var(--download-video-background);color:var(--download-video-foreground);border:1px dashed var(--theme-color);z-index:2;font-size:10pt;width:200px;padding:8px;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;pointer-events:none;opacity:0}.download-video .size-warning:hover .size-warning-tip{opacity:1}.download-video .episode-list .v-checkbox{padding:4px 8px;margin:4px 0;position:relative;background-color:transparent}.download-video .episode-list .v-checkbox.checked{background-color:#8882}.download-video .episode-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.download-video .episode-list{overflow:auto;max-height:320px}.download-video button.list-tool{padding:4px;line-height:1;font-size:12pt;margin:0 4px}.download-video .episode-header h2{flex-grow:1}.download-video .selected-count{width:64px;text-align:right}.download-video .aria2-rpc .mdi{margin-left:8px;font-size:14pt;line-height:1}.download-video .aria2-rpc{position:relative}.download-video .rpc-settings{position:absolute;display:flex;flex-direction:column;align-items:stretch;color:var(--download-video-foreground);background:#fff;bottom:120%;left:50%;cursor:initial;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;transform-origin:bottom;transform:translateX(-50%) scale(.9);opacity:0;pointer-events:none;padding:8px;z-index:3;transition:.3s cubic-bezier(.18,.89,.32,1.28);width:120%}body.dark .download-video .rpc-settings{background:#282828}.download-video .rpc-settings>*{margin:8px}.download-video .rpc-settings.show{opacity:1;transform:translateX(-50%) scale(1);pointer-events:initial}.download-video .rpc-settings input[type=text]{background:0 0;color:var(--download-video-foreground);border:1px solid #8884;padding:4px;margin-left:8px}.download-video .rpc-settings input[type=text]:focus{border-color:var(--theme-color)}.download-video .rpc-settings .operations{display:flex;align-items:center;justify-content:space-evenly}.download-video .final-dir{word-break:break-all}.download-video .rpc-settings-item{display:flex;align-items:center;justify-content:space-between;white-space:nowrap}.download-video .rpc-settings-item input[type=text]{flex-grow:1;margin-left:24px}.download-video button.cancel-download,.download-video button.start-download{margin-top:8px}.download-video .direct-download-header{align-self:stretch;display:flex;justify-content:space-between;align-items:center}body.dark .download-video .direct-download .progress .foreground{background:linear-gradient(to right,var(--theme-color-70),var(--theme-color))}`; onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.html"] = `

下载视频

单个视频
批量导出
警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.
预计大小: {{displaySize}}
格式
清晰度
弹幕
首选编码
ffmpeg支持

直接下载

{{speed}}
{{progressPercent}}%

选集

{{selectedEpisodeCount}}/{{episodeList.length}}

导出

{{showRpcSettings ? '取消' : 'aria2 RPC'}}

aria2 RPC

配置

主机
端口
密钥
限速
默认路径
路径
最终路径: {{rpcSettings.baseDir + rpcSettings.dir}}
方法
开始下载
{{saveRpcSettingsText}}
`; -onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}this.batchExtractor=new s;this.batch=true;this.episodeList=(await this.batchExtractor.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); +onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}const a=this.batchExtractor=new s;this.batch=true;this.episodeList=(await a.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/dpi-img.vue.min.js"] = (()=>{return(t,s)=>{const e=``;return{export:Object.assign({template:e},{props:["size","src","blur","root","rootMargin","threshold"],data(){return{srcset:null,actualSrc:null}},methods:{calcSrc(){if(!this.src||!this.size){return null}const t=this.src.substring(this.src.lastIndexOf(".")+1);this.srcset=getDpiSourceSet(this.src,this.size,t);this.actualSrc=this.src}},mounted(){const t={root:this.root,rootMargin:this.rootMargin||"200px",threshold:this.threshold};const s=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){this.calcSrc();s.disconnect()}})},t);s.observe(this.$el)},computed:{width(){if(typeof this.size==="object"&&"width"in this.size){return this.size.width}return null},height(){if(typeof this.size==="object"&&"height"in this.size){return this.size.height}return null}}})}}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-danmaku.min.js"] = (()=>{return(e,a)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}Observer.videoChange(async()=>{const e=await SpinQuery.select(".bui-collapse-wrap");if(e&&e.classList.contains("bui-collapse-wrap-folded")){const e=await SpinQuery.select(".bui-collapse-header");e.click()}})}})(); onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/expand-description.min.css"] = `.play-up-info .play-up-self,.video-desc .info{height:auto!important}.play-up-info .play-up-self-btn,.video-desc .btn{display:none!important}`; diff --git a/min/batch-download.min.js b/min/batch-download.min.js index 655232846..e45b30a5d 100644 --- a/min/batch-download.min.js +++ b/min/batch-download.min.js @@ -1 +1 @@ -(()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); \ No newline at end of file +(()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}.flv`,split:i,dir:r.baseDir+r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}.flv\n split=${i}\n`.trim()})}).join("\n")}\n`.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return[]}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return[]}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return[]}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title.replace(/[\/\\:\*\?"<>\|]/g," "),totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o;class c{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:c}}}})(); \ No newline at end of file diff --git a/min/bundle.json b/min/bundle.json index 28de01163..af22b5f98 100644 --- a/min/bundle.json +++ b/min/bundle.json @@ -10,7 +10,7 @@ "auto-continue.min.js": "96CD47C367D7397CE1467A69764409BAEFF16E8F535BC8E15523CD0B8A86687E", "auto-draw.min.js": "AE72CF2623DF2D15AD4AF82D125FFAF7EF5B1E6B36D9E9AC646AC98AA6AA8698", "auto-play.min.js": "DC9938AC15DADDC9D88DCA0C9BE64BE142C37D32CB85E42E23DAB2A7378531E5", - "batch-download.min.js": "A0F979F33A06E23D3800525CF70700170565EBD98579CE394ECE4CC66AAEEB5A", + "batch-download.min.js": "2937E9622D79F7512405902587DDDA3C647453ADAE7B18245CE934808FA02712", "biliplus-redirect.min.js": "9882D14DAC5C103212A101A5168883C41B4B3B2737FD5F222DC343D0304FF8AF", "blackboard.min.js": "8BB9CCDE72302AE7DE39D66F9231EFB82BA27DDA799BA4AAAC06F6DE802661BF", "blackboard.vue.min.js": "8F1984AB69B029701DC88F33568EF1881D0C54EEC72D65EA3029CF2F68BD6674", @@ -47,7 +47,7 @@ "download-video-package.min.js": "B9BFBA2E5E9267ED901359BEE10E0B92619A429F4B09F7E96B15EE6B9CD81A30", "download-video.min.css": "95FF9DA3C1FFF1C1134D70AE3BB609049B7D5D3FBB71CAAAE84C8742C51AD841", "download-video.min.html": "DDC359FD5551C01572CDE93CF7A8C63D4DD956568930AA97AA2C6FFEA7A6FC2A", - "download-video.min.js": "0066CA903974E0F70EB4588D9A4E9FE697C7D63815C4A95056B95A2D79EBA246", + "download-video.min.js": "BB4E9B82DB9109ACC45488F081BE5875CB3BE2EC351E8DFE3192CA911AEB6A1F", "dpi-img.vue.min.js": "3D9D93079365DCABA8DC8970F051AD1A7F25C3EFFF850CD1000C4312E9B910DD", "expand-danmaku.min.js": "B21658C40085AEA8DC49652AE62EB8610BB2EBEAF7A9C9AF69EF3B11E08EEC8D", "expand-description.min.css": "58C7710A50521B80F7D872BDC4C652610D84C4FABC6874BA66DA37B4F8759224", diff --git a/min/bundle.zip b/min/bundle.zip index 1e9bfb91a32ccfa6a53a050de51978ceca17bcf0..035da76d0284d26ae9f7e9a6defe2cf6ad2553c5 100644 GIT binary patch delta 2301 zcmY*a3s6+&6~6Z_guSo=?(Sg$3xU?Q36aV&)krAIYekCIM@r0$1kILLh|5EuiUt+O z8q$n4F(mmCZ6lf32Ic)+V3DW1-!ILWYJ*AY*hx)rOlms`_FR_9m=;uJtpo(6pp)`+Tw~#Gn-fLurutc*9k5l(UqST^PqA9^^8->!t!D4iH_X~ned3Pe*2EHPqG+=w zO6hfyrln-oS;gYS;>_|8iwld|HtQ@GKeiM|nEkoXyD@@r*Jd%wrf_viPIi7lfF%O^ zGG!g=t@2vYQgY8Kv$(Rjv1nLUu(-2$uz0epWYMzdSoF4gRx+A?m?uIjC{aq@Sz5Ex z7xAs+iTVoi6^AfZK_+n*G?f%1&1YbHCB;eM&nwyoUzL+PIxERvjKhseij?kV0tYo#7cGwKKUrrhnSM%XkoU5j-QlK4W)f51a z8d{@D?htUShIF{qM;>^#hWw@f#G<%{qxkvPiq_);#qMmQggcFr4+3f_NEI<7;nf+* zfbbS}o?FY#Bk@WtMM?ks8dI#*PpMQwswHnPx_Zg?XG*J$yYi0S>UI_s(FouFUUOcy zHMaA0S#|8~J)ErLgx<$c9sNf2$gmnO466f>ZRhJY*0Vu3QtRp0;xSa$(e zHWA_V8uENtiS}DOFed2x!3uhWG*OIOSb;30=4J+GW@R9{mkiihDC>3KS!xPpA+0di zl8wMd`VngT$O#`dk*}0>5RuK?RL^D#7L719Q=F#!kSwHI_UGhf7Np^H1qGt6nNd-U z(PlEKW>3m6{z>-3mR`=TcA7nHu9Q8IU?W%Qn+oi-QKT4-H*J(4eOiZ`Hcn{19zSiN zDB0M=o^!0J!T3iN`QoJ(E{)U*V=E_nsfB{2&JM>Sq*HdnTQz*a%2u|S?o_s;oksg* z0c!_kLgaw#;sDb-Y#?fIsg=y)RYe&PG{p!FspQBWYvUX@4dGN9d1Fr--!QkdFuS}w zA`2P6&%}pyQ=clIp5g`Wqz872u4WGdhTCc8XW8JK!ojmzkP| z#a>#4;(oqkxX{(p@Lj2k3LO@~zq4d#gx%z1r3LTj+j1ODHFU6_%~;<-Ch6u0?C+om^(VJo zg-qjyY#2wljk9c_&fD#_yrm%6y^{|;f#6QsAo?S{lT7N65;kB?ad=$3oZ6GP)kWd1IXB&e zy=e!tEV)=H=UL{ooDkd1cJE+!HzTO;fg8?s(>m4b8Coo4XbGQn^B8}et3}j4trynz zP!O}nt{&!+9GvZ;%~Iwc@aG z{sm!|nRR-~aO5&irU8SOdHi04M;{YgA-49>2Gy8di=cMxs%0eiarGBwG1*u+BA0PK~j3QPKa7&FyXQle(f)=M2w7&RP8^d>U zfV~di!xsZ&Ry}!Ni<>M7U z$0er=j>XUj8Ko~TIu;(I6vEJo8s&TDAL!mN>HV-~iW6uaC4Z+5SuY^KP49&}qujSp zH$7f)V++5FY_V;OD^ic_F|POUIy8)NE!6l@QC@g_oHjDu9UkWgWGD_t#(55}k8@Ek z?!b--uJHPHW_qrY6V^>IL`>K|L1y*LZ}mdHHFFt3H4}Wp%NU=aCq#G1lN7JIP_4(_ zYP}D#CTR_$^vooeUe~EdZl_+4uzHSbagtBz;5S8K@-yRlp&-YSUw|c6&z~ZHm!@k= zd$3F}*q3;$Zi?Ar;U>nW_%-|AZD^*sF#*^z&8d{&)HJ^+(_xsL=9at#-3)CKW05pN z;i}kpLRmaRq-KU2TZwBkJlmy-gf9{~#ichdW|sU_^SotxitU!T^8{~+nK(boGa(lc z(hHbsiUz# nJNQO-g^xdr&?_8;`7Ghxv-D%UeT73aBsx>Ok7qlmT^~So`sg?=-vb?~!{J=QT78oZbRY}<=@(W#LhKAw7n8KLK(Ao-J zl($}(A%B(>Gyk^qF??D^%cLuX)~3Rlc-%TCx6*$7Z6%O9yrxb)A4Kt86}e$Ar&0X zYd<+w6`xd)zc_^U3J!QDTr24%F$*!36e7)jg1_;qJt)gULi~<5@m3po&&xiM6ceyv z$NukIT?7a8KgZ$t)8#U0JJ!g)O;yb9D%MmnjZwT;MN!hG9=u;gbKu{|>|M@~QGVF3 z#kGE|4^n;)snf?P#8r^{ zod4^RU(s5PduJ)kH9J!g64FylDch4FwviV+_b95zFP3ZeC_>_%^!PMfucp~ZZzm0o z){wVUmW`)1T=T&iGKm=&uc1}?fA3XBH>FwN!D3&PF;Zs1%+yS|R4(6&tOVo@S+H)Mn zihW2wM`3PjbJ>q&d!lI!kj81BY#I<`0`O z+DvA*SHI$&?eWQua1wXp^LEZM-&zeKTR6cXNN8bhAL3LCEz?ze<0`zFn7utd9aX3K ziZd+@j zO9%6v7*$+yqxd#9cknp+9w$0D#!!6M!6nVWyiRVP%rOIE#|+*mZs6`L=wz?D2dL~M zv;5&B11ygWUU2JThBxqH7nwy1a=W;{j=|o=p@rdzV=2b+ZeETdrm$UB|_OR#QEG%yoa0k-IGpDP%r&nG8Z|8 z_j)NnT3q5326}0cc<|#sKE_v2G5*xU2e${Az^*(`$ijZ%Xt9YSYeFmmM zekGc*VUSb5u35#RW>v-GDvrxO$X~6)=penQeA=%HnU?sSnV1;=zZ)Xs)CXTr=-@lR zy*@F=GKP2}27HS{L;Tn+y@kFZF3c9_hnY$zqKEnEF)T&FFqh;jj0{t_n1@*-v`o&6 zAZ&@?7O{+QVQ=He2;c3II6`F{Q=Ax6(j}hxzJDN$$FbeS>|Dtzu?Pv5_)0`(66R&{ zs9j#ip$|KDj$@2>ByA1?E>o!6*ZCw&i~`fnOv?@o74y|Te3^`T_d|}2#NDQ?mR-(y lGs0@|bKJkoQ5-l*h(Ahx_~R80?Ens3p}AASPZJNU{{gCvTTuW2 diff --git a/min/download-video.min.js b/min/download-video.min.js index 19fa20763..3686cf8c1 100644 --- a/min/download-video.min.js +++ b/min/download-video.min.js @@ -1 +1 @@ -(()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}this.batchExtractor=new s;this.batch=true;this.episodeList=(await this.batchExtractor.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); \ No newline at end of file +(()=>{return(t,e)=>{const{getFriendlyTitle:s}=e.import("title");const{VideoInfo:a,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:o}=e.import("download-video-package");class n{async getDashUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${c.aid}&cid=${c.cid}&otype=json`}}}class r extends n{async getDashUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&qn=${t}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=56995872&cid=99547543&otype=json&fourk=1&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=&otype=json`}}}class l extends n{constructor(t){super();this.ep=t}async getDashUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}async getUrl(t){if(t){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&qn=${t}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${c.aid}&cid=${c.cid}&otype=json&ep_id=${this.ep}`}}}const c={entity:new n,aid:"",cid:""};let d=[];let p=null;class h{constructor(t,e,s){this.quality=t;this.internalName=e;this.displayName=s}async downloadInfo(t=false){const e=new u(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const s=t.accept_format.split(",");const a=t.accept_description;const i=e.map((t,e)=>{return new h(t,s[e],a[e])});return i}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}return h.parseFormats(e.data||e.result||e)}static async getAvailableFormats(){const t=await c.entity.getUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const s=e.data||e.result||e;return h.parseFormats(s)}}class u{constructor(t,e){this.fragmentSplitFactor=6*2;this.workingXhr=null;this.progressMap=new Map;this.format=t;this.fragments=e||[];this.videoSpeed=new f(this)}get danmakuOption(){return t.downloadVideoDefaultDanmaku}get ffmpegOption(){return t.downloadVideoFfmpegSupport}get isDash(){return this.fragments.some(t=>t.url.includes(".m4s"))}get totalSize(){return this.fragments.map(t=>t.size).reduce((t,e)=>t+e)}async fetchVideoInfo(s=false){if(!s){const t=await c.entity.getUrl(this.format.quality);const e=await Ajax.getTextWithCredentials(t);const s=JSON.parse(e.replace(/http:/g,"https:"));const a=s.data||s.result||s;if(a.quality!==this.format.quality){throw new Error("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const i=a.durl;this.fragments=i.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragment:s,getDashInfo:a}=await e.importAsync("video-dash");const i=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);console.log(i.videoDashes);const o=(()=>{const e=e=>e.videoCodec===t.downloadVideoDashCodec;if(i.videoDashes.some(e)){return i.videoDashes.filter(e).sort(ascendingSort(t=>t.bandWidth))[0]}else{return i.videoDashes.sort(ascendingSort(t=>t.bandWidth))[0]}})();const n=i.audioDashes.sort(descendingSort(t=>t.bandWidth))[0];this.fragments=[s(o),s(n)]}return this.fragments}updateProgress(){const t=this.progressMap?[...this.progressMap.values()].reduce((t,e)=>t+e,0)/this.totalSize:0;if(t>1||t<0){console.error(`[下载视频] 进度异常: ${t}`,this.progressMap.values())}this.progress&&this.progress(t)}cancelDownload(){this.videoSpeed.stopMeasure();if(this.workingXhr!==null){this.workingXhr.forEach(t=>t.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(t){const e=[];const s=this.isDash?4*1024*1024:16*1024*1024;let a;if(t.size<=s*6){a=t.size/this.fragmentSplitFactor}else{a=s}let i=0;const o=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i{const a=new XMLHttpRequest;a.open("GET",t.url);a.responseType="arraybuffer";a.withCredentials=false;a.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${o(a)}下载进度: ${t.loaded}/${r} bytes loaded, ${n}`);this.progressMap.set(a,t.loaded);this.updateProgress()});a.addEventListener("load",()=>{if((""+a.status)[0]==="2"){console.log(`[下载视频] 视频片段${o(a)}下载完成`);e(a.response)}else{s(`视频片段${o(a)}请求失败, response = ${a.status}`)}});a.addEventListener("abort",()=>s("canceled"));a.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${o(a)}下载失败: ${n}`);this.progressMap.set(a,0);this.updateProgress();a.open("GET",t.url);a.setRequestHeader("Range",n);a.send()});a.setRequestHeader("Range",n);this.progressMap.set(a,0);a.send();this.workingXhr.push(a)}));i=Math.round(i+a)+1}return Promise.all(e)}async copyUrl(){const t=this.fragments.map(t=>t.url).reduce((t,e)=>t+"\r\n"+e);GM.setClipboard(t,"text")}async showUrl(){const t=this.fragments.map(t=>`\n${t.url}\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`复制全部`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:s(),totalSize:this.fragments.map(t=>t.size).reduce((t,e)=>t+e),referer:document.URL.replace(window.location.search,"")}]);if(t){GM.setClipboard(e,"text")}else{const t=new Blob([e],{type:"text/json"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.json`,t);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}async exportAria2(a=false){if(a){const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,a);await i.emit();const n=t.aria2RpcOption;const r=this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}const i=[];if(n.secretKey!==""){i.push(`token:${n.secretKey}`)}i.push([t.url]);i.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${s()}${a}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:n.baseDir+n.dir||undefined,"max-download-limit":n.maxDownloadLimit||undefined});const o=encodeURIComponent(`${s()}${a}`);return{params:i,id:o}});const{sendRpc:l}=await e.importAsync("aria2-rpc");await l(r)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let a="";if(this.fragments.length>1){a=" - "+(e+1)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${s()}${a}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const a=await this.downloadDanmaku();const i=new o({ffmpeg:this.ffmpegOption});i.add(`${s()}.txt`,e);i.add(s()+"."+this.danmakuOption.toLowerCase(),a);await i.emit(`${s()}.zip`)}}extension(t){const e=t||this.fragments[0];const s=[".flv",".mp4",".m4s"].find(t=>e.url.includes(t));if(s){return s}else{console.warn("No extension detected.");return".flv"}}async downloadDanmaku(){if(this.danmakuOption!=="无"){const t=new i(c.cid);await t.fetchInfo();if(this.danmakuOption==="XML"){return t.rawXML}else{const{convertToAss:s}=await e.importAsync("download-danmaku");return s(t.rawXML)}}else{return null}}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const s=await this.downloadFragment(e);t.push(s)}if(t.length<1){throw new Error("下载失败.")}const e=new o({ffmpeg:this.ffmpegOption});const a=s();t.forEach((s,i)=>{let o;const n=this.fragments[i];if(t.length>1){o=`${a} - ${i+1}${this.extension(n)}`}else{o=`${a}${this.extension(n)}`}e.add(o,new Blob(Array.isArray(s)?s:[s],{type:this.extension(n)===".flv"?"video/x-flv":"video/mp4"}))});const i=await this.downloadDanmaku();e.add(`${s()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);await e.emit(a+".zip");this.progress&&this.progress(0);this.videoSpeed.stopMeasure()}}class f{constructor(t){this.lastProgress=0;this.measureInterval=1e3;this.workingDownloader=t}startMeasure(){this.intervalTimer=setInterval(()=>{const t=this.workingDownloader.progressMap?[...this.workingDownloader.progressMap.values()].reduce((t,e)=>t+e,0):0;const e=t-this.lastProgress;if(this.speedUpdate!==undefined){this.speedUpdate(formatFileSize(e)+"/s")}this.lastProgress=t},this.measureInterval)}stopMeasure(){clearInterval(this.intervalTimer)}}async function m(){const t=await SpinQuery.select(()=>(unsafeWindow||window).aid);const e=await SpinQuery.select(()=>(unsafeWindow||window).cid);if(!(t&&e)){return false}c.aid=t;c.cid=e;if(document.URL.includes("bangumi")){c.entity=new r}else if(document.URL.includes("cheese")){const t=document.URL.match(/cheese\/play\/ep([\d]+)/);c.entity=new l(t[1])}else{c.entity=new n}try{d=await h.getAvailableFormats()}catch(t){return false}return true}async function w(){p=d[0];e.applyStyle("downloadVideoStyle");dq("#download-video").addEventListener("click",()=>{dq(".download-video").classList.toggle("opened");dq(".gui-settings-mask").click()});dq("#download-video").addEventListener("mouseover",()=>{document.body.insertAdjacentHTML("beforeend",e.import("downloadVideoHtml"));g()},{once:true})}async function g(){let n;const r=new Vue({el:".download-video",components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{downloadSingle:true,coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:p.displayName,items:d.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},ffmpegModel:{value:t.downloadVideoFfmpegSupport,items:["无","文件列表","文件列表+脚本"]},progressPercent:0,size:"获取大小中",blobUrl:"",episodeList:[],downloading:false,speed:"",batch:false,rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:""},computed:{displaySize(){if(typeof this.size==="string"){return this.size}return formatFileSize(this.size)},sizeWarning(){if(typeof this.size==="string"){return false}return this.size>1073741824},selectedEpisodeCount(){return this.episodeList.filter(t=>t.checked).length},dash(){return this.dashModel.value==="dash"}},methods:{close(){this.$el.classList.remove("opened")},danmakuOptionChange(){t.downloadVideoDefaultDanmaku=this.danmakuModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){console.log("dash change");t.downloadVideoFormat=this.dashModel.value;const e=this.dashModel.value;let s=[];if(e==="flv"){s=await h.getAvailableFormats()}else{s=await h.getAvailableDashFormats()}d=s;[p]=e;this.qualityModel.items=s.map(t=>t.displayName);[this.qualityModel.value]=this.qualityModel.items;await this.formatChange()},async formatChange(){console.log("format change");const t=this.getFormat();try{this.size="获取大小中";const e=await t.downloadInfo(this.dash);this.size=e.totalSize}catch(t){this.size="获取大小失败";throw t}},getFormat(){const t=d.find(t=>t.displayName===this.qualityModel.value);if(!t){console.error(`No format found. model value = ${this.qualityModel.value}`);return null}return t},async exportData(t){if(this.busy===true){return}try{this.busy=true;if(!this.downloadSingle){await this.exportBatchData(t);return}const e=this.getFormat();const s=await e.downloadInfo(this.dash);switch(t){case"copyLink":await s.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await s.showUrl();break;case"aria2":await s.exportAria2(false);break;case"aria2RPC":await s.exportAria2(true);break;case"copyVLD":await s.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await s.exportData(false);break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const a=this.episodeList;if(a.every(t=>t.checked===false)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}const n=t=>{const e=a.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const r=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const s=new o;try{if(this.danmakuModel.value==="XML"){for(const t of a.filter(n)){const e=new i(t.cid);await e.fetchInfo();s.add(t.title+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of a.filter(n)){const a=new i(e.cid);await a.fetchInfo();s.add(e.title+".ass",await t(a.rawXML))}}await s.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`)}finally{t.dismiss()}}const l=Toast.info("获取链接中...","批量导出");this.batchExtractor.itemFilter=n;let c;try{switch(t){case"aria2":c=await this.batchExtractor.collectAria2(r,l);await o.single(s(false)+".txt",new Blob([c],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await this.batchExtractor.collectAria2(r,l,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await this.batchExtractor.collectData(r,l),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":c=await this.batchExtractor.collectData(r,l);await o.single(s(false)+".json",new Blob([c],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;default:return}}catch(t){logError(t)}finally{l.dismiss()}},async checkBatch(){const t=["/www.bilibili.com/bangumi","/www.bilibili.com/video/av"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:s}=await e.importAsync("batch-download");if(await s.test()!==true){this.batch=false;this.episodeList=[];return}const a=this.batchExtractor=new s;this.batch=true;this.episodeList=(await a.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,index:e,checked:true}})},cancelDownload(){if(n){n.cancelDownload()}},async startDownload(){const t=this.getFormat();try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});n=e;await e.download();this.lastDirectDownloadLink=o.lastPackageUrl}catch(t){if(t!=="canceled"){logError(t)}this.progressPercent=0}finally{this.downloading=false;this.speed=""}},selectAllEpisodes(){this.episodeList.forEach(t=>t.checked=true)},unselectAllEpisodes(){this.episodeList.forEach(t=>t.checked=false)},inverseAllEpisodes(){this.episodeList.forEach(t=>t.checked=!t.checked)},toggleRpcSettings(){this.showRpcSettings=!this.showRpcSettings},saveRpcSettings(){if(this.rpcSettings.host===""){this.rpcSettings.host="127.0.0.1"}if(this.rpcSettings.port===""){this.rpcSettings.port="6800"}t.aria2RpcOption=this.rpcSettings;const e=t.aria2RpcOptionProfiles.find(e=>e.name===t.aria2RpcOptionSelectedProfile);if(e){Object.assign(e,this.rpcSettings);t.aria2RpcOptionProfiles=t.aria2RpcOptionProfiles}this.saveRpcSettingsText="已保存";setTimeout(()=>this.saveRpcSettingsText="保存配置",2e3)},updateProfile(e){t.aria2RpcOption=this.rpcSettings=_.omit(e,"name")}},async mounted(){}});Observer.videoChange(async()=>{r.close();r.batch=false;r.downloadSingle=true;const t=dq("#download-video");const e=await m();t.style.display=e?"flex":"none";if(!e){return}r.aid=c.aid;r.cid=c.cid;try{const t=new a(c.aid);await t.fetchInfo();r.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){r.coverUrl=EmptyImageUrl}r.dashChange();await r.checkBatch()})}return{widget:{content:`\n`,condition:m,success:w}}}})(); \ No newline at end of file diff --git a/src/video/download-video/batch-download.d.ts b/src/video/download-video/batch-download.d.ts deleted file mode 100644 index 235f1f868..000000000 --- a/src/video/download-video/batch-download.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface BatchItem { - title: string - aid: string - cid: string -} -export class BatchExtractor { - itemList: BatchItem[] - itemFilter: (item: BatchItem) => boolean - static test(): Promise - getItemList(): Promise - collectData(format: any, toast: Toast): Promise - collectAria2(format: any, toast: Toast, rpc?: boolean): Promise -} \ No newline at end of file diff --git a/src/video/download-video/batch-download.js b/src/video/download-video/batch-download.ts similarity index 77% rename from src/video/download-video/batch-download.js rename to src/video/download-video/batch-download.ts index cc07e9ba7..bba715dfb 100644 --- a/src/video/download-video/batch-download.js +++ b/src/video/download-video/batch-download.ts @@ -1,18 +1,29 @@ const fragmentSplitFactor = 12 -class Batch { - constructor () { - this.itemList = [] - this.itemFilter = () => true - } - async getItemList() {} - async collectData () {} - async collectAria2 (quality, rpc) { - const json = JSON.parse(await this.collectData(quality)) +interface BatchItem { + aid: number | string + cid: number | string + title: string +} +interface RawItemFragment { length: number, size: number, url: string } +interface RawItem { + fragments: RawItemFragment[] + title: string + totalSize: number + cid: number | string + referer: string +} +abstract class Batch { + itemList: BatchItem[] = [] + itemFilter: (item: BatchItem) => boolean = () => true + abstract async getItemList(): Promise + abstract async collectData(quality: number | string): Promise + async collectAria2(quality: number | string, rpc: boolean) { + const json: RawItem[] = JSON.parse(await this.collectData(quality)) if (rpc) { const option = settings.aria2RpcOption const { sendRpc } = await import('./aria2-rpc') for (const item of json) { - const params = item.fragments.map((fragment, index) => { + const params = item.fragments.map((fragment: { url: string }, index: number) => { let indexNumber = '' if (item.fragments.length > 1) { indexNumber = ' - ' + (index + 1) @@ -43,8 +54,8 @@ class Batch { # Generated by Bilibili Evolved Video Export # https://github.com/the1812/Bilibili-Evolved/ ${json.map(item => { - return item.fragments.map(f => { - return ` + return item.fragments.map(f => { + return ` ${f.url} referer=${item.referer} user-agent=${UserAgent} @@ -58,7 +69,7 @@ ${f.url} } } class VideoEpisodeBatch extends Batch { - static async test () { + static async test() { if (!document.URL.includes('/www.bilibili.com/video/av')) { return false } @@ -72,14 +83,14 @@ class VideoEpisodeBatch extends Batch { const json = await Ajax.getJson(api) if (json.code !== 0) { Toast.error(`获取视频选集列表失败, message=${json.message}`, '批量下载') - return '' + return [] } const pages = json.data.pages if (pages === undefined) { Toast.error(`获取视频选集列表失败, 没有找到选集信息.`, '批量下载') - return '' + return [] } - this.itemList = pages.map(page => { + this.itemList = pages.map((page: any) => { return { title: `P${page.page} ${page.part}`, cid: page.cid, @@ -88,7 +99,7 @@ class VideoEpisodeBatch extends Batch { }) return this.itemList } - async collectData (quality) { + async collectData(quality: number | string) { const result = [] for (const item of (await this.getItemList()).filter(this.itemFilter)) { const url = `https://api.bilibili.com/x/player/playurl?avid=${item.aid}&cid=${item.cid}&qn=${quality}&otype=json` @@ -97,7 +108,7 @@ class VideoEpisodeBatch extends Batch { if (data.quality !== quality) { console.warn(`${item.title} 不支持所选画质, 已回退到较低画质. (quality=${data.quality})`) } - const fragments = data.durl.map(it => { + const fragments: RawItemFragment[] = data.durl.map((it: any) => { return { length: it.length, size: it.size, @@ -116,7 +127,7 @@ class VideoEpisodeBatch extends Batch { } } class BangumiBatch extends Batch { - static async test () { + static async test() { return document.URL.includes('/www.bilibili.com/bangumi') } async getItemList() { @@ -126,19 +137,19 @@ class BangumiBatch extends Batch { const metaUrl = document.querySelector("meta[property='og:url']") if (metaUrl === null) { Toast.error('获取番剧数据失败: 无法找到 Season ID', '批量下载') - return '' + return [] } - const seasonId = metaUrl.getAttribute('content').match(/play\/ss(\d+)/)[1] + const seasonId = metaUrl.getAttribute('content')!.match(/play\/ss(\d+)/)![1] if (seasonId === undefined) { Toast.error('获取番剧数据失败: 无法解析 Season ID', '批量下载') - return '' + return [] } const json = await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${seasonId}`) if (json.code !== 0) { Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${json.message}`, '批量下载') - return '' + return [] } - this.itemList = json.result.main_section.episodes.map((it, index) => { + this.itemList = json.result.main_section.episodes.map((it: any, index: number) => { return { aid: it.aid, cid: it.cid, @@ -147,7 +158,7 @@ class BangumiBatch extends Batch { }) return this.itemList } - async collectData (quality) { + async collectData(quality: string | number) { const result = [] for (const item of (await this.getItemList()).filter(this.itemFilter)) { const url = `https://api.bilibili.com/pgc/player/web/playurl?avid=${item.aid}&cid=${item.cid}&qn=${quality}&otype=json` @@ -156,7 +167,7 @@ class BangumiBatch extends Batch { if (data.quality !== quality) { console.warn(`${item.title} 不支持所选画质, 已回退到较低画质. (quality=${data.quality})`) } - const fragments = data.durl.map(it => { + const fragments: RawItemFragment[] = data.durl.map((it: any) => { return { length: it.length, size: it.size, @@ -175,22 +186,19 @@ class BangumiBatch extends Batch { } } const extractors = [BangumiBatch, VideoEpisodeBatch] -let ExtractorClass = null +let ExtractorClass: new() => Batch export class BatchExtractor { - constructor() { - this.itemFilter = () => true - } - static async test () { + itemFilter: (item: BatchItem) => boolean = () => true + static async test() { for (const e of extractors) { if (await e.test() === true) { ExtractorClass = e return true } } - ExtractorClass = null return false } - getExtractor () { + getExtractor() { if (ExtractorClass === null) { logError('[批量下载] 未找到合适的解析模块.') throw new Error(`[Batch Download] module not found.`) @@ -199,17 +207,17 @@ export class BatchExtractor { extractor.itemFilter = this.itemFilter return extractor } - async getItemList () { + async getItemList() { const extractor = this.getExtractor() return await extractor.getItemList() } - async collectData (format, toast) { + async collectData(format: { quality: number | string }, toast: Toast) { const extractor = this.getExtractor() const result = await extractor.collectData(format.quality) toast.dismiss() return result } - async collectAria2 (format, toast, rpc) { + async collectAria2(format: { quality: number | string }, toast: Toast, rpc: boolean) { const extractor = this.getExtractor() const result = await extractor.collectAria2(format.quality, rpc) toast.dismiss() diff --git a/src/video/download-video/download-video.ts b/src/video/download-video/download-video.ts index c451f77ea..7707252d0 100644 --- a/src/video/download-video/download-video.ts +++ b/src/video/download-video/download-video.ts @@ -834,16 +834,16 @@ async function loadPanel() { this.episodeList = [] return } - this.batchExtractor = new BatchExtractor() + const batchExtractor = this.batchExtractor = new BatchExtractor() this.batch = true - this.episodeList = (await this.batchExtractor.getItemList()).map((item: EpisodeItem, index: number) => { + this.episodeList = (await batchExtractor.getItemList()).map((item, index) => { return { aid: item.aid, cid: item.cid, title: item.title, index, checked: true, - } + } as EpisodeItem }) }, cancelDownload() {