mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
1 line
6.9 KiB
JavaScript
1 line
6.9 KiB
JavaScript
(()=>{return(t,e)=>{const{formatTitle:i}=e.import("title");const s=12;const a=[".mp4",".m4a"];class n{constructor(t){this.config=t;this.itemList=[]}static formatTitle(e){const s=t.batchFilenameFormat;const a=i(s,true,e);return escapeFilename(a," ")}async getRawItems(t){return JSON.parse(await this.collectData(t))}extension(t,e){const i=[".flv",".mp4"].find(e=>t.includes(e));if(i){return i}else if(t.includes(".m4s")){return a[e]}else{return".flv"}}async collectAria2(i,a){const n=await this.getRawItems(i);const{getNumber:r}=await e.importAsync("get-number");if(a){const i=t.aria2RpcOption;const{sendRpc:a}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,a)=>{let n="";if(t.fragments.length>1&&!e.url.includes(".m4s")){n=" - "+r(a+1,t.fragments.length)}const o=[];if(i.secretKey!==""){o.push(`token:${i.secretKey}`)}o.push([e.url]);o.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}${this.extension(e.url,a)}`,split:s,dir:i.baseDir+i.dir||undefined,"max-download-limit":i.maxDownloadLimit||undefined});const c=encodeURIComponent(`${t.title}${n}`);return{params:o,id:c}});await a(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,i)=>{let a="";if(t.fragments.length>1&&!e.url.includes(".m4s")){a=` - ${r(i+1,t.fragments.length)}`}return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}${a}${this.extension(e.url,i)}\n split=${s}\n`.trim()}).join("\n")}).join("\n")}\n`.trim()}}}class r extends n{constructor(){super(...arguments);this.aid=unsafeWindow.aid}static async test(){if(document.URL.startsWith("https://www.bilibili.com/video/")){return await SpinQuery.select("#multi_page")!==null}return false}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${this.aid}`;const i=await Ajax.getJson(t);if(i.code!==0){Toast.error(`获取视频选集列表失败, message=${i.message}`,"批量下载");return[]}const s=i.data.pages;if(s===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return[]}const{getNumber:a}=await e.importAsync("get-number");this.itemList=s.map(t=>{return{title:`P${t.page} ${t.part}`,titleParameters:{n:a(t.page,this.itemList.length),ep:t.part},cid:t.cid,aid:this.aid}});return this.itemList}async collectData(t){const i=[];for(const s of(await this.getItemList()).filter(this.config.itemFilter)){const a=this.config.api?this.config.api(s.aid,s.cid,t):`https://api.bilibili.com/x/player/playurl?avid=${s.aid}&cid=${s.cid}&qn=${t}&otype=json`;const r=await Ajax.getJsonWithCredentials(a);const o=r.data||r.result||r;if(o.quality!==t){console.warn(`${s.title} 不支持所选画质, 已回退到较低画质. (quality=${o.quality})`)}let c;if(o.durl){c=o.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}})}else{const{getDashInfo:i,dashToFragments:s}=await e.importAsync("video-dash");const n=await i(a,typeof t==="string"?parseInt(t):t,true);c=s(n)}i.push({fragments:c,title:n.formatTitle(s.titleParameters),totalSize:c.map(t=>t.size).reduce((t,e)=>t+e),cid:s.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(i)}}class o extends n{constructor(t){super(t);this.mainVideo=new r(t);this.mainVideo.aid="78976165";this.spVideo=new r(t);this.spVideo.aid="78979124"}static async test(){return document.URL.includes("//www.bilibili.com/blackboard/bnj2020.html")}async getItemList(){return(await this.mainVideo.getItemList()).concat(await this.spVideo.getItemList())}async collectData(t){return(await this.mainVideo.collectData(t)).concat(await this.spVideo.collectData(t))}}class c extends n{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 i=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(i===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return[]}const s=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${i}`);if(s.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${s.message}`,"批量下载");return[]}const{getNumber:a}=await e.importAsync("get-number");this.itemList=s.result.main_section.episodes.map((t,e)=>{const i=t.long_title?t.title:(e+1).toString();const s=t.long_title?t.long_title:t.title;return{aid:t.aid,cid:t.cid,title:`${i} - ${s}`,titleParameters:{n:a(parseInt(i),this.itemList.length),ep:s}}});return this.itemList}async collectData(t){const i=[];for(const s of(await this.getItemList()).filter(this.config.itemFilter)){const a=this.config.api?this.config.api(s.aid,s.cid,t):`https://api.bilibili.com/pgc/player/web/playurl?avid=${s.aid}&cid=${s.cid}&qn=${t}&otype=json`;const r=await Ajax.getJsonWithCredentials(a);const o=r.data||r.result||r;if(o.quality!==t){console.warn(`${s.title} 不支持所选画质, 已回退到较低画质. (quality=${o.quality})`)}let c;if(o.durl){c=o.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}})}else{const{getDashInfo:i,dashToFragments:s}=await e.importAsync("video-dash");const n=await i(a,typeof t==="string"?parseInt(t):t);c=s(n)}i.push({fragments:c,title:n.formatTitle(s.titleParameters),totalSize:c.map(t=>t.size).reduce((t,e)=>t+e),cid:s.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(i)}}class l extends r{constructor(){super(...arguments);this.items=[]}async getItemList(){const{VideoInfo:t}=await e.importAsync("video-info");const{getNumber:i}=await e.importAsync("get-number");const s=await Promise.all(this.items.map(async e=>{const s=new t(e);await s.fetchInfo();return s.pages.map((t,a)=>{return{aid:e,cid:t.cid,titleParameters:{n:i(a+1,s.pages.length),ep:s.pages.length>1?t.title:"",title:s.title},title:`P${a+1} ${t.title}`}})}));console.log(_.flatten(_.cloneDeep(s)));return _.flatten(s)}}const u=[c,r,o];let m;class d{constructor(t){this.config=Object.assign({itemFilter:()=>true},t)}static async test(){for(const t of u){if(await t.test()===true){m=t;return true}}return false}getExtractor(){if(m===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new m(this.config);return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async getRawItems(t){const e=this.getExtractor();return await e.getRawItems(t.quality)}async collectData(t,e){const i=this.getExtractor();const s=await i.collectData(t.quality);e.dismiss();return s}async collectAria2(t,e,i=false){const s=this.getExtractor();const a=await s.collectAria2(t.quality,i);e.dismiss();return a}formatTitle(t){return n.formatTitle(t)}}return{export:{BatchExtractor:d,ManualInputBatch:l}}}})(); |