Bilibili-Evolved/min/download-video.min.js
2020-09-14 23:05:12 +08:00

1 line
25 KiB
JavaScript

(()=>{return(t,e)=>{const{getFriendlyTitle:a}=e.import("title");const{VideoInfo:s,DanmakuInfo:i}=e.import("video-info");const{DownloadVideoPackage:n}=e.import("download-video-package");class o{async getApiGenerator(t=false){function e(e,a,s){if(t){if(s){return`https://api.bilibili.com/x/player/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json&fourk=1&fnver=0&fnval=16`}else{return`https://api.bilibili.com/x/player/playurl?avid=${e}&cid=${a}&otype=json&fourk=1&fnver=0&fnval=16`}}else{if(s){return`https://api.bilibili.com/x/player/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${e}&cid=${a}&otype=json`}}}return e.bind(this)}async getDashUrl(t){return(await this.getApiGenerator(true))(c.aid,c.cid,t)}async getUrl(t){return(await this.getApiGenerator())(c.aid,c.cid,t)}}class r extends o{async getApiGenerator(t=false){function e(e,a,s){if(t){if(s){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json&fourk=1&fnval=16`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${e}&cid=${a}&otype=json&fourk=1&fnval=16`}}else{if(s){return`https://api.bilibili.com/pgc/player/web/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json`}else{return`https://api.bilibili.com/pgc/player/web/playurl?avid=${e}&cid=${a}&qn=&otype=json`}}}return e.bind(this)}}class l extends o{constructor(t){super();this.ep=t}async getApiGenerator(t=false){function e(e,a,s){if(t){if(s){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${e}&cid=${a}&otype=json&ep_id=${this.ep}&fnver=0&fnval=16`}}else{if(s){return`https://api.bilibili.com/pugv/player/web/playurl?avid=${e}&cid=${a}&qn=${s}&otype=json&ep_id=${this.ep}`}else{return`https://api.bilibili.com/pugv/player/web/playurl?avid=${e}&cid=${a}&otype=json&ep_id=${this.ep}`}}}return e.bind(this)}}const c={entity:new o,aid:"",cid:""};let d=[];let h=null;class p{constructor(t,e,a){this.quality=t;this.internalName=e;this.displayName=a}async downloadInfo(t=false){const e=new m(this);await e.fetchVideoInfo(t);return e}static parseFormats(t){const e=t.accept_quality;const a=t.accept_format.split(",");const s=t.accept_description;const i=e.map((t,e)=>{return new p(t,a[e],s[e])});return i}static async filterFormats(t){return t}static async getAvailableDashFormats(){const t=await c.entity.getDashUrl();const e=await Ajax.getJsonWithCredentials(t);if(e.code!==0){throw new Error("获取清晰度信息失败.")}const a=e.data||e.result||e;return await p.filterFormats(p.parseFormats(a))}static async getAvailableFormats(){const{BannedResponse:t,throwBannedError:a}=await e.importAsync("batch-warning");try{const e=await c.entity.getUrl();const s=await Ajax.getJsonWithCredentials(e);if(s.code!==0){throw new Error("获取清晰度信息失败.")}const i=s.data||s.result||s;return await p.filterFormats(p.parseFormats(i))}catch(e){if(e.message.includes(t.toString())){a()}throw e}}}const u=[new p(120,"4K","超清 4K"),new p(116,"1080P60","高清 1080P60"),new p(112,"1080P+","高清 1080P+"),new p(80,"1080P","高清 1080P"),new p(74,"720P60","高清 720P60"),new p(64,"720P","高清 720P"),new p(32,"480P","清晰 480P"),new p(16,"360P","流畅 360P")];class m{constructor(t,e){this.subtitle=false;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 subtitleOption(){return t.downloadVideoDefaultSubtitle}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(t=false){if(!t){const t=await c.entity.getUrl(this.format.quality);const a=await Ajax.getTextWithCredentials(t);const s=JSON.parse(a.replace(/http:/g,"https:"));const i=s.data||s.result||s;const n=this.format.quality;if(i.quality!==n){const{throwQualityError:t}=await e.importAsync("quality-errors");t(n)}const o=i.durl;this.fragments=o.map(t=>{return{length:t.length,size:t.size,url:t.url,backupUrls:t.backup_url}})}else{const{dashToFragments:t,getDashInfo:a}=await e.importAsync("video-dash");const s=await a(await c.entity.getDashUrl(this.format.quality),this.format.quality);this.fragments=t(s)}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 a=this.isDash?4*1024*1024:16*1024*1024;let s;if(t.size<=a*6){s=t.size/this.fragmentSplitFactor}else{s=a}let i=0;const n=t=>[...this.progressMap.keys()].indexOf(t)+1;while(i<t.size){const a=Math.min(t.size-1,Math.round(i+s));const o=`bytes=${i}-${a}`;const r=a-i+1;e.push(new Promise((e,a)=>{const s=new XMLHttpRequest;s.open("GET",t.url);s.responseType="arraybuffer";s.withCredentials=false;s.addEventListener("progress",t=>{console.log(`[下载视频] 视频片段${n(s)}下载进度: ${t.loaded}/${r} bytes loaded, ${o}`);this.progressMap.set(s,t.loaded);this.updateProgress()});s.addEventListener("load",()=>{if((""+s.status)[0]==="2"){console.log(`[下载视频] 视频片段${n(s)}下载完成`);e(s.response)}else{a(`视频片段${n(s)}请求失败, response = ${s.status}`)}});s.addEventListener("abort",()=>a("canceled"));s.addEventListener("error",()=>{console.error(`[下载视频] 视频片段${n(s)}下载失败: ${o}`);this.progressMap.set(s,0);this.updateProgress();s.open("GET",t.url);s.setRequestHeader("Range",o);s.send()});s.setRequestHeader("Range",o);this.progressMap.set(s,0);s.send();this.workingXhr.push(s)}));i=Math.round(i+s)+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<a class="download-link" href="${t.url}">${t.url}</a>\n`).reduce((t,e)=>t+"\r\n"+e);Toast.success(t+`<a class="link" id="copy-link" style="cursor: pointer;margin: 8px 0 0 0;">复制全部</a>`,"显示链接");const e=await SpinQuery.select("#copy-link");e.addEventListener("click",async()=>{await this.copyUrl()})}async exportIdm(){const{toIdmFormat:t}=await e.importAsync("idm-support");const s=t([this]);const i=await this.downloadDanmaku();const o=await this.downloadSubtitle();const r=new n;r.add(`${a()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,i);r.add(`${a()}.${this.subtitleOption==="ASS"?"ass":"json"}`,o);r.add(`${a()}.ef2`,s);await r.emit(`${a()}.zip`)}async exportData(t=false){const e=JSON.stringify([{fragments:this.fragments,title:a(),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 s=await this.downloadDanmaku();const i=new n;i.add(`${a()}.json`,t);i.add(a()+"."+this.danmakuOption.toLowerCase(),s);await i.emit(`${a()}.zip`)}}async exportAria2(s=false){const{getNumber:i}=await e.importAsync("get-number");if(s){const s=await this.downloadDanmaku();const o=await this.downloadSubtitle();const r=new n;r.add(`${a()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,s);r.add(`${a()}.${this.subtitleOption==="ASS"?"ass":"json"}`,o);await r.emit();const l=t.aria2RpcOption;const c=this.fragments.map((t,e)=>{let s="";if(this.fragments.length>1&&!this.isDash){s=" - "+i(e+1,this.fragments.length)}const n=[];if(l.secretKey!==""){n.push(`token:${l.secretKey}`)}n.push([t.url]);n.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${a()}${s}${this.extension(t)}`,split:this.fragmentSplitFactor,dir:l.baseDir+l.dir||undefined,"max-download-limit":l.maxDownloadLimit||undefined});const o=encodeURIComponent(`${a()}${s}`);return{params:n,id:o}});const{sendRpc:d}=await e.importAsync("aria2-rpc");await d(c)}else{const t=`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${this.fragments.map((t,e)=>{let s="";if(this.fragments.length>1&&!this.isDash){s=" - "+i(e+1,this.fragments.length)}return`\n${t.url}\n referer=${document.URL.replace(window.location.search,"")}\n user-agent=${UserAgent}\n out=${a()}${s}${this.extension(t)}\n split=${this.fragmentSplitFactor}\n`.trim()}).join("\n")}\n`.trim();const e=new Blob([t],{type:"text/plain"});const s=await this.downloadDanmaku();const o=await this.downloadSubtitle();const r=new n;r.add(`${a()}.txt`,e);r.add(a()+"."+this.danmakuOption.toLowerCase(),s);r.add(a()+"."+this.subtitleOption.toLowerCase(),o);await r.emit(`${a()}.zip`)}}extension(t){const e=t||this.fragments[0];const a=[".flv",".mp4"].find(t=>e.url.includes(t));if(a){return a}else if(e.url.includes(".m4s")){return this.fragments.indexOf(e)===0?".mp4":".m4a"}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:a}=await e.importAsync("download-danmaku");return a(t.rawXML)}}else{return null}}async downloadSubtitle(){if(this.subtitle&&this.subtitleOption!=="无"){const{getSubtitleConfig:t,getSubtitleList:a}=await e.importAsync("download-subtitle");const[s,i]=await t();const n=await a(c.aid,c.cid);const o=n.find(t=>t.language===i)||n[0];const r=await Ajax.getJson(o.url);const l=r.body;if(this.subtitleOption==="JSON"){return l}else{const{SubtitleConverter:t}=await e.importAsync("subtitle-converter");const a=new t(s);const i=await a.convertToAss(l);return i}}return null}async download(){this.workingXhr=[];this.progressMap=new Map;this.updateProgress();const t=[];this.videoSpeed.startMeasure();for(const e of this.fragments){const a=await this.downloadFragment(e);t.push(a)}if(t.length<1){throw new Error("下载失败.")}const s=a();const i=new n;const{getNumber:o}=await e.importAsync("get-number");t.forEach((e,a)=>{let n;const r=this.fragments[a];if(t.length>1&&!this.isDash){n=`${s} - ${o(a+1,t.length)}${this.extension(r)}`}else{n=`${s}${this.extension(r)}`}i.add(n,new Blob(Array.isArray(e)?e:[e]))});const r=await this.downloadDanmaku();i.add(`${a()}.${this.danmakuOption==="ASS"?"ass":"xml"}`,r);const l=await this.downloadSubtitle();i.add(`${a()}.${this.subtitleOption==="ASS"?"ass":"json"}`,l);await i.emit(s+".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 w(){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 o}try{d=await p.getAvailableFormats()}catch(t){return false}return true}const g=e=>{const a=t.downloadVideoQuality;const s=e.find(t=>t.quality===a);if(s){return s}const i=e.filter(t=>t.quality<a).shift();if(i){return i}return e.shift()};async function y(){h=g(d);e.applyStyle("downloadVideoStyle");const t=dq("#download-video");t.addEventListener("click",()=>{const t=dq(".download-video");t.classList.toggle("opened");window.scroll(0,0);dq(".gui-settings-mask").click()});t.addEventListener("mouseover",()=>{b()},{once:true})}async function b(){let r;const l=[{name:"single",displayName:"单个视频"},{name:"batch",displayName:"批量导出"},{name:"manual",displayName:"手动输入"}];const f=new Vue({template:e.import("downloadVideoHtml"),components:{VDropdown:()=>e.importAsync("v-dropdown.vue"),VCheckbox:()=>e.importAsync("v-checkbox.vue"),RpcProfiles:()=>e.importAsync("aria2-rpc-profiles.vue")},data:{batch:false,subtitle:false,selectedTab:l[0],coverUrl:EmptyImageUrl,aid:c.aid,cid:c.cid,dashModel:{value:t.downloadVideoFormat,items:["flv","dash"]},qualityModel:{value:h.displayName,items:d.map(t=>t.displayName)},manualQualityModel:{value:u[1].displayName,items:u.map(t=>t.displayName)},danmakuModel:{value:t.downloadVideoDefaultDanmaku,items:["无","XML","ASS"]},subtitleModel:{value:t.downloadVideoDefaultSubtitle,items:["无","JSON","ASS"]},codecModel:{value:t.downloadVideoDashCodec,items:["AVC/H.264","HEVC/H.265"]},progressPercent:0,size:"获取大小中",blobUrl:"",lastCheckedEpisodeIndex:-1,episodeList:[],downloading:false,speed:"",rpcSettings:t.aria2RpcOption,showRpcSettings:false,busy:false,saveRpcSettingsText:"保存配置",enableDash:t.enableDashDownload,lastDirectDownloadLink:"",manualInputText:""},computed:{tabs(){if(this.batch){return l}const t=[...l];_.remove(t,t=>t.name==="batch");return t},manualInputItems(){const t=this.manualInputText.split(/\s/g);const e=t.map(t=>t.match(/av(\d+)/i)||t.match(/^(\d+)$/));return _.uniq(e.filter(t=>t!==null).map(t=>t[1]))},downloadSingle(){return this.selectedTab.name==="single"},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},subtitleOptionChange(){t.downloadVideoDefaultSubtitle=this.subtitleModel.value},async codecChange(){t.downloadVideoDashCodec=this.codecModel.value;await this.formatChange()},async dashChange(){const e=t.downloadVideoFormat=this.dashModel.value;let a=[];if(e==="flv"){a=await p.getAvailableFormats()}else{a=await p.getAvailableDashFormats()}d=a;h=g(d);this.qualityModel.items=a.map(t=>t.displayName);this.qualityModel.value=this.qualityModel.items[d.indexOf(h)];await this.formatChange()},async formatChange(e=false){const a=this.getFormat();if(e){t.downloadVideoQuality=a.quality}try{this.size="获取大小中";const t=await a.downloadInfo(this.dash);this.size=t.totalSize}catch(t){this.size="获取大小失败";throw t}},getManualFormat(){let t;t=u.find(t=>t.displayName===this.manualQualityModel.value);if(!t){console.error(`No format found. model value = ${this.manualQualityModel.value}`);return null}return t},getFormat(){let t;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.selectedTab.name==="batch"){await this.exportBatchData(t);return}if(this.selectedTab.name==="manual"){await this.exportManualData(t);return}const s=this.getFormat();const i=await s.downloadInfo(this.dash);i.subtitle=this.subtitle;switch(t){case"copyLink":await i.copyUrl();Toast.success("已复制链接到剪贴板.","下载视频",3e3);break;case"showLink":await i.showUrl();break;case"aria2":await i.exportAria2(false);break;case"aria2RPC":await i.exportAria2(true);break;case"copyVLD":await i.exportData(true);Toast.success("已复制VLD数据到剪贴板.","下载视频",3e3);break;case"exportVLD":await i.exportData(false);break;case"ffmpegFragments":if(i.fragments.length<2){Toast.info("当前视频没有分段.","分段合并",3e3)}else{const{getFragmentsList:t}=await e.importAsync("ffmpeg-support");const s=new n;s.add("ffmpeg-files.txt",t(i.fragments.length,a(),i.fragments.map(t=>i.extension(t))));await s.emit()}break;case"idm":await i.exportIdm();break;default:break}}catch(t){logError(t)}finally{this.busy=false}},async exportBatchData(t){const s=this.episodeList;const{MaxBatchSize:o,showBatchWarning:r}=await e.importAsync("batch-warning");if(s.every(t=>!t.checked)){Toast.info("请至少选择1集或以上的数量!","批量导出",3e3);return}if(s.filter(t=>t.checked).length>o){r("批量导出");return}const l=t=>{const e=s.find(e=>e.cid===t.cid);if(e===undefined){return false}return e.checked};const d=this.batchExtractor;const h=this.getFormat();if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","批量导出");const a=new n;try{if(this.danmakuModel.value==="XML"){for(const t of s.filter(l)){const e=new i(t.cid);await e.fetchInfo();a.add(d.formatTitle(t.titleParameters)+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of s.filter(l)){const s=new i(e.cid);await s.fetchInfo();a.add(d.formatTitle(e.titleParameters)+".ass",await t(s.rawXML))}}await a.emit(this.cid+".danmakus.zip")}catch(t){logError(`弹幕下载失败`);throw t}finally{t.dismiss()}}if(this.subtitleModel.value!=="无"){const t=Toast.info("下载字幕中...","批量导出");const a=new n;try{const{getSubtitleConfig:i,getSubtitleList:n}=await e.importAsync("download-subtitle");const[o,r]=await i();for(const t of s.filter(l)){const s=await n(t.aid,t.cid);const i=s.find(t=>t.language===r)||s[0];if(i===undefined){continue}const l=await Ajax.getJson(i.url);const c=l.body;if(this.subtitleModel.value==="JSON"){a.add(d.formatTitle(t.titleParameters)+".json",c)}else{const{SubtitleConverter:s}=await e.importAsync("subtitle-converter");const i=new s(o);const n=await i.convertToAss(c);a.add(d.formatTitle(t.titleParameters)+".ass",n)}}await a.emit(this.cid+".subtitles.zip")}catch(t){logError(`字幕下载失败`);throw t}finally{t.dismiss()}}const p=Toast.info("获取链接中...","批量导出");d.config.itemFilter=l;d.config.api=await c.entity.getApiGenerator(this.dash);let u;try{switch(t){case"idm":const s=await d.getRawItems(h);const{toIdmFormat:i}=await e.importAsync("idm-support");u=i(s);await n.single(a(false)+".ef2",new Blob([u],{type:"text/plain"}));return;case"aria2":u=await d.collectAria2(h,p,false);await n.single(a(false)+".txt",new Blob([u],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});return;case"aria2RPC":await d.collectAria2(h,p,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);return;case"copyVLD":GM.setClipboard(await d.collectData(h,p),{mimetype:"text/plain"});Toast.success("已复制批量vld数据到剪贴板.","批量导出",3e3);return;case"exportVLD":u=await d.collectData(h,p);await n.single(a(false)+".json",new Blob([u],{type:"text/json"}),{ffmpeg:this.ffmpegOption});return;case"ffmpegFragments":{const t=await d.getRawItems(h);if(t.every(t=>t.fragments.length<2)){Toast.info("所有选择的分P都没有分段.","分段列表",3e3);return}const s=new m(h,t[0].fragments);const{getBatchFragmentsList:i}=await e.importAsync("ffmpeg-support");const o=i(t,this.dash||s.extension());if(!o){Toast.info("所有选择的分P都没有分段.","分段列表",3e3);return}const r=new n;for(const[t,e]of o.entries()){r.add(t,e)}await r.emit(escapeFilename(`${a(false)}.zip`))}break;case"ffmpegEpisodes":{const t=await d.getRawItems(h);const a=new m(h,t[0].fragments);const{getBatchEpisodesList:s}=await e.importAsync("ffmpeg-support");const i=s(t,this.dash||a.extension());const o=new n;o.add("ffmpeg-files.txt",i);await o.emit()}break;default:return}}catch(t){logError(t)}finally{p.dismiss()}},async exportManualData(t){const{MaxBatchSize:a,showBatchWarning:s}=await e.importAsync("batch-warning");if(this.manualInputItems.length===0){Toast.info("请至少输入一个有效的视频链接!","手动输入",3e3);return}if(this.manualInputItems.length>a){s("手动输入");return}const{ManualInputBatch:r}=await e.importAsync("batch-download");const l=new r({api:await(new o).getApiGenerator(this.dash),itemFilter:()=>true});l.items=this.manualInputItems;if(this.danmakuModel.value!=="无"){const t=Toast.info("下载弹幕中...","手动输入");const a=new n;try{if(this.danmakuModel.value==="XML"){for(const t of await l.getItemList()){const e=new i(t.cid);await e.fetchInfo();a.add(r.formatTitle(t.titleParameters)+".xml",e.rawXML)}}else{const{convertToAss:t}=await e.importAsync("download-danmaku");for(const e of await l.getItemList()){const s=new i(e.cid);await s.fetchInfo();a.add(r.formatTitle(e.titleParameters)+".ass",await t(s.rawXML))}}await a.emit("manual-exports.danmakus.zip")}catch(t){logError(`弹幕下载失败`);throw t}finally{t.dismiss()}}if(this.subtitleModel.value!=="无"){const t=Toast.info("下载字幕中...","批量导出");const a=new n;try{const{getSubtitleConfig:s,getSubtitleList:i}=await e.importAsync("download-subtitle");const[n,o]=await s();for(const t of await l.getItemList()){const s=await i(t.aid,t.cid);const l=s.find(t=>t.language===o)||s[0];const c=await Ajax.getJson(l.url);const d=c.body;if(this.subtitleModel.value==="JSON"){a.add(r.formatTitle(t.titleParameters)+".json",d)}else{const{SubtitleConverter:s}=await e.importAsync("subtitle-converter");const i=new s(n);const o=await i.convertToAss(d);a.add(r.formatTitle(t.titleParameters)+".ass",o)}}await a.emit("manual-exports.subtitles.zip")}catch(t){logError(`字幕下载失败`);throw t}finally{t.dismiss()}}const c=Toast.info("获取链接中...","手动输入");try{switch(t){default:case"aria2":{const t=await l.collectAria2(this.getManualFormat().quality,false);await n.single("manual-exports.txt",new Blob([t],{type:"text/plain"}),{ffmpeg:this.ffmpegOption});break}case"aria2RPC":{await l.collectAria2(this.getManualFormat().quality,true);Toast.success(`成功发送了批量请求.`,"aria2 RPC",3e3);break}case"idm":{const t=await l.getRawItems(this.getManualFormat().quality);const{toIdmFormat:a}=await e.importAsync("idm-support");const s=a(t);await n.single("manual-exports.ef2",new Blob([s],{type:"text/plain"}));break}}}catch(t){logError(t)}finally{c.dismiss()}},async checkBatch(){const t=["//www.bilibili.com/bangumi","//www.bilibili.com/video","//www.bilibili.com/blackboard/bnj2020.html"];if(!t.some(t=>document.URL.includes(t))){this.batch=false;this.episodeList=[];return}const{BatchExtractor:a}=await e.importAsync("batch-download");const{MaxBatchSize:s}=await e.importAsync("batch-warning");if(await a.test()!==true){this.batch=false;this.episodeList=[];return}const i=this.batchExtractor=new a;this.batch=true;this.episodeList=(await i.getItemList()).map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.title,titleParameters:t.titleParameters,index:e,checked:e<s}})},async checkSubtitle(){const{getSubtitleList:t}=await e.importAsync("download-subtitle");const a=await t(c.aid,c.cid);this.subtitle=a.length>0},cancelDownload(){if(r){r.cancelDownload()}},async startDownload(){const t=this.getFormat();if(t.quality===120){Toast.info("4K视频不支持直接下载, 请使用下方的导出选项.","下载视频",5e3);return}try{this.downloading=true;const e=await t.downloadInfo(this.dash);e.subtitle=this.subtitle;e.videoSpeed.speedUpdate=(t=>this.speed=t);e.progress=(t=>{this.progressPercent=Math.trunc(t*100)});r=e;await e.download();this.lastDirectDownloadLink=n.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)},shiftToggleEpisodes(t,e){if(!t.shiftKey||this.lastCheckedEpisodeIndex===-1){console.log("set lastCheckedEpisodeIndex",e);this.lastCheckedEpisodeIndex=e;return}if(t.shiftKey&&this.lastCheckedEpisodeIndex!==-1){this.episodeList.slice(Math.min(this.lastCheckedEpisodeIndex,e)+1,Math.max(this.lastCheckedEpisodeIndex,e)).forEach(t=>{t.checked=!t.checked});console.log("shift toggle",Math.min(this.lastCheckedEpisodeIndex,e)+1,Math.max(this.lastCheckedEpisodeIndex,e));this.lastCheckedEpisodeIndex=e;t.preventDefault()}},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(){}});const y=f.$mount().$el;document.body.insertAdjacentElement("beforeend",y);Observer.videoChange(async()=>{f.close();f.batch=false;f.selectedTab=l[0];const t=dq("#download-video");const e=await w();t.style.display=e?"flex":"none";if(!e){return}f.aid=c.aid;f.cid=c.cid;try{const t=new s(c.aid);await t.fetchInfo();f.coverUrl=t.coverUrl.replace("http:","https:")}catch(t){f.coverUrl=EmptyImageUrl}f.dashChange();f.checkSubtitle();await f.checkBatch()})}return{widget:{content:`\n<button class="gui-settings-flat-button" style="position: relative; z-index: 100;" id="download-video">\n<i class="icon-download"></i>\n<span>下载视频</span>\n</button>`,condition:w,success:y}}}})();