mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
1 line
7.8 KiB
JavaScript
1 line
7.8 KiB
JavaScript
(()=>(t,e)=>{function i(t,e,i){if(e in t){Object.defineProperty(t,e,{value:i,enumerable:true,configurable:true,writable:true})}else{t[e]=i}return t}const{formatTitle:s}=e.import("title");const a=12;const n=[".mp4",".m4a"];class r{constructor(t){this.config=t;i(this,"itemList",[])}static formatTitle(e){const i=t.batchFilenameFormat;const a=s(i,true,e);return escapeFilename(a," ")}async getRawItems(t){const{BannedResponse:i,throwBannedError:s}=await e.importAsync("batch-warning");try{const e=await this.collectData(t);return JSON.parse(e)}catch(t){if(t.message.includes(i.toString())){s()}throw t}}extension(t,e){const i=[".flv",".mp4"].find((e=>t.includes(e)));if(i){return i}else if(t.includes(".m4s")){return n[e]}else{return".flv"}}async collectAria2(i,s){const n=await this.getRawItems(i);const{getNumber:r}=await e.importAsync("get-number");if(s){const i=t.aria2RpcOption;const{sendRpc:s,parseRpcOptions:o}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map(((e,s)=>{let n="";if(t.fragments.length>1&&!e.url.includes(".m4s")){n=" - "+r(s+1,t.fragments.length)}const c=[];if(i.secretKey!==""){c.push(`token:${i.secretKey}`)}c.push([e.url]);c.push({referer:document.URL.replace(window.location.search,""),"user-agent":UserAgent,out:`${t.title}${n}${this.extension(e.url,s)}`,split:a,dir:i.dir||undefined,...o(i.other)});const l=encodeURIComponent(`${t.title}${n}`);return{params:c,id:l}}));await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map((t=>t.fragments.map(((e,i)=>{let s="";if(t.fragments.length>1&&!e.url.includes(".m4s")){s=` - ${r(i+1,t.fragments.length)}`}return`\n${e.url}\n referer=${t.referer}\n user-agent=${UserAgent}\n out=${t.title}${s}${this.extension(e.url,i)}\n split=${a}\n`.trim()})).join("\n"))).join("\n")}\n`.trim()}}}class o extends r{constructor(...t){super(...t);i(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=>({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 n=await Ajax.getJsonWithCredentials(a);const o=n.data||n.result||n;if(o.quality!==t){console.warn(`${s.title} 不支持所选画质, 已回退到较低画质. (quality=${o.quality})`)}let c;if(o.durl){c=o.durl.map((t=>({length:t.length,size:t.size,url:t.url})))}else if(o.dash){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)}else{throw new Error(`获取链接失败: ${n.code} ${n.message}`)}i.push({fragments:c,title:r.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 c extends r{constructor(t){super(t);i(this,"mainVideo",void 0);i(this,"spVideo",void 0);this.mainVideo=new o(t);this.mainVideo.aid="78976165";this.spVideo=new o(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 l extends o{constructor(t){super(t);this.config=t;i(this,"videos",_.get(unsafeWindow,"__INITIAL_STATE__.videoSections",[]).map((t=>t.episodes)).flat())}static async test(){return document.URL.includes("//www.bilibili.com/festival/2021bnj")}async getItemList(){const{getNumber:t}=await e.importAsync("get-number");return this.videos.map((({aid:e,cid:i,title:s},a)=>({title:`P${a+1} ${s}`,titleParameters:{n:t(a+1,this.videos.length),ep:s},aid:e,cid:i})))}}class u 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 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(parseFloat(i),this.itemList.length,t.title),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 n=await Ajax.getJsonWithCredentials(a);const o=n.data||n.result||n;if(o.quality!==t){console.warn(`${s.title} 不支持所选画质, 已回退到较低画质. (quality=${o.quality})`)}let c;if(o.durl){c=o.durl.map((t=>({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:r.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 m extends o{constructor(...t){super(...t);i(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)=>({aid:e,cid:t.cid,titleParameters:{aid:e,cid:t.cid.toString(),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("%cClass ManualInputBatch%c, data: ","color:yellow;",_.flatten(_.cloneDeep(s)));return _.flatten(s)}}const d=[u,o,c,l];let g;class p{constructor(t){i(this,"config",void 0);this.config=Object.assign({itemFilter:()=>true},t)}static async test(){for(const t of d){if(await t.test()===true){g=t;return true}}return false}getExtractor(){if(g===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new g(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 r.formatTitle(t)}}return{export:{BatchExtractor:p,ManualInputBatch:m}}})(); |