This commit is contained in:
the1812 2019-08-24 12:29:39 +08:00
parent 58548e2c61
commit 3c04c9dc87
11 changed files with 17 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -282,7 +282,7 @@ const settings = {
port: '6800',
method: 'get',
skipByDefault: false,
maxDownloadLimit: '0',
maxDownloadLimit: '',
},
searchHistory: [],
seedsToCoins: true,

View File

@ -282,7 +282,7 @@ const settings = {
port: '6800',
method: 'get',
skipByDefault: false,
maxDownloadLimit: '0',
maxDownloadLimit: '',
},
searchHistory: [],
seedsToCoins: true,

View File

@ -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":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0",out:`${t.title}${n}.flv`,split:i,dir:r.dir||undefined,"max-download-limit":r.maxDownloadLimit});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=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0\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,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,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 l{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:l}}}})();
(()=>{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":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0",out:`${t.title}${n}.flv`,split:i,dir: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=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0\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,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,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 l{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:l}}}})();

View File

@ -1 +1 @@
<div class=download-video><a v-bind:href=blobUrl id=video-complete style="display: none"></a><div class=header><h1>下载视频</h1><i class="mdi mdi-close"v-on:click=close()></i></div><div v-if=batch class=tabs><div class="tab download-single"v-bind:class="{active: downloadSingle}"v-on:click="downloadSingle = true">单个视频</div><div class="tab download-batch"v-bind:class="{active: !downloadSingle}"v-on:click="downloadSingle = false">批量导出</div></div><div v-show=downloadSingle class=info><img v-bind:src=coverUrl class=cover><div class=title><span class=size><div v-if=sizeWarning class=size-warning><i class="mdi mdi-alert-circle"></i><div class=size-warning-tip>警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.</div></div>预计大小: {{displaySize}}</span></div></div><div class=options><div class=option-item>清晰度<v-dropdown v-on:change=formatChange() v-bind:items=qualityModel.items v-bind:value.sync=qualityModel.value></v-dropdown></div><div class=option-item>弹幕<v-dropdown v-on:change=danmakuOptionChange() v-bind:items=danmakuModel.items v-bind:value.sync=danmakuModel.value></v-dropdown></div></div><div class=separator></div><div v-show=downloadSingle class=direct-download><div class=direct-download-header><h2>直接下载</h2><span class=download-speed>{{speed}}</span></div><button v-if=!downloading class="primary start-download"v-on:click=startDownload()>开始</button><button v-else class="primary cancel-download"v-on:click=cancelDownload()>取消</button><div class=progress><div class=background><div class=foreground v-bind:style="{width: progressPercent + '%'}"></div></div><span class=percent>{{progressPercent}}%</span></div></div><div v-show=!downloadSingle class=batch-download><div class=episode-header><h2>选集</h2><button class=list-tool title=全选 v-on:click=selectAllEpisodes()><i class="mdi mdi-checkbox-multiple-marked-circle"></i></button><button class=list-tool title=全不选 v-on:click=unselectAllEpisodes()><i class="mdi mdi-checkbox-multiple-blank-circle-outline"></i></button><button class=list-tool title=反选 v-on:click=inverseAllEpisodes()><i class="mdi mdi-circle-slice-4"></i></button><span class=selected-count>{{selectedEpisodeCount}}/{{episodeList.length}}</span></div><div class=episode-list><v-checkbox v-for="ep of episodeList"v-bind:key=ep.index v-bind:title=ep.title v-bind:checked.sync=ep.checked></v-checkbox></div></div><div class=separator></div><div class=exports><h2>导出</h2><div class=actions v-bind:class="{busy: busy}"><button class=copy-link v-bind:disabled="downloadSingle ? null : 'disabled'"v-on:click="exportData('copyLink')">复制链接</button><button class=aria2-file v-on:click="exportData('aria2')">导出aria2</button><button class=vld-copy v-on:click="exportData('copyVLD')">复制vld数据</button><button class=vld-export v-on:click="exportData('exportVLD')">导出vld数据</button><div class="button aria2-rpc"v-on:click.self=toggleRpcSettings()>{{showRpcSettings ? '取消' : '导出aria2 RPC'}}<i :class="{'mdi-close': showRpcSettings, 'mdi-chevron-right': !showRpcSettings}"class=mdi v-on:click.self=toggleRpcSettings()></i><div class=rpc-settings v-bind:class="{show: showRpcSettings}"><h1>aria2 RPC 配置</h1><div class=rpc-settings-item>主机<input type=text v-model=rpcSettings.host placeholder=127.0.0.1></div><div class=rpc-settings-item>端口<input type=text v-model=rpcSettings.port placeholder=6800></div><div class=rpc-settings-item>密钥<input type=text v-model=rpcSettings.secretKey></div><div class=rpc-settings-item>单任务限速<input type=text v-model=rpcSettings.maxDownloadLimit placeholder=></div><div class=rpc-settings-item>总体限速<input type=text v-model=rpcSettings.maxOverallDownloadLimit placeholder=></div><div class=rpc-settings-item>路径<input type=text v-model=rpcSettings.dir></div><div class=rpc-settings-item>方法<v-dropdown style="text-transform: uppercase;"v-bind:items="['get', 'post']"v-bind:value.sync=rpcSettings.method></v-dropdown></div><div class="primary button"v-on:click="saveRpcSettings();toggleRpcSettings();exportData('aria2RPC')">确定</div></div></div></div></div></div>
<div class=download-video><a v-bind:href=blobUrl id=video-complete style="display: none"></a><div class=header><h1>下载视频</h1><i class="mdi mdi-close"v-on:click=close()></i></div><div v-if=batch class=tabs><div class="tab download-single"v-bind:class="{active: downloadSingle}"v-on:click="downloadSingle = true">单个视频</div><div class="tab download-batch"v-bind:class="{active: !downloadSingle}"v-on:click="downloadSingle = false">批量导出</div></div><div v-show=downloadSingle class=info><img v-bind:src=coverUrl class=cover><div class=title><span class=size><div v-if=sizeWarning class=size-warning><i class="mdi mdi-alert-circle"></i><div class=size-warning-tip>警告: 过大的视频大小会在直接下载时占用大量内存, 并可能导致浏览器标签页崩溃. 请考虑降低清晰度或使用导出选项.</div></div>预计大小: {{displaySize}}</span></div></div><div class=options><div class=option-item>清晰度<v-dropdown v-on:change=formatChange() v-bind:items=qualityModel.items v-bind:value.sync=qualityModel.value></v-dropdown></div><div class=option-item>弹幕<v-dropdown v-on:change=danmakuOptionChange() v-bind:items=danmakuModel.items v-bind:value.sync=danmakuModel.value></v-dropdown></div></div><div class=separator></div><div v-show=downloadSingle class=direct-download><div class=direct-download-header><h2>直接下载</h2><span class=download-speed>{{speed}}</span></div><button v-if=!downloading class="primary start-download"v-on:click=startDownload()>开始</button><button v-else class="primary cancel-download"v-on:click=cancelDownload()>取消</button><div class=progress><div class=background><div class=foreground v-bind:style="{width: progressPercent + '%'}"></div></div><span class=percent>{{progressPercent}}%</span></div></div><div v-show=!downloadSingle class=batch-download><div class=episode-header><h2>选集</h2><button class=list-tool title=全选 v-on:click=selectAllEpisodes()><i class="mdi mdi-checkbox-multiple-marked-circle"></i></button><button class=list-tool title=全不选 v-on:click=unselectAllEpisodes()><i class="mdi mdi-checkbox-multiple-blank-circle-outline"></i></button><button class=list-tool title=反选 v-on:click=inverseAllEpisodes()><i class="mdi mdi-circle-slice-4"></i></button><span class=selected-count>{{selectedEpisodeCount}}/{{episodeList.length}}</span></div><div class=episode-list><v-checkbox v-for="ep of episodeList"v-bind:key=ep.index v-bind:title=ep.title v-bind:checked.sync=ep.checked></v-checkbox></div></div><div class=separator></div><div class=exports><h2>导出</h2><div class=actions v-bind:class="{busy: busy}"><button class=copy-link v-bind:disabled="downloadSingle ? null : 'disabled'"v-on:click="exportData('copyLink')">复制链接</button><button class=aria2-file v-on:click="exportData('aria2')">导出aria2</button><button class=vld-copy v-on:click="exportData('copyVLD')">复制vld数据</button><button class=vld-export v-on:click="exportData('exportVLD')">导出vld数据</button><div class="button aria2-rpc"v-on:click.self=toggleRpcSettings()>{{showRpcSettings ? '取消' : '导出aria2 RPC'}}<i :class="{'mdi-close': showRpcSettings, 'mdi-chevron-right': !showRpcSettings}"class=mdi v-on:click.self=toggleRpcSettings()></i><div class=rpc-settings v-bind:class="{show: showRpcSettings}"><h1>aria2 RPC 配置</h1><div class=rpc-settings-item>主机<input type=text v-model=rpcSettings.host placeholder=127.0.0.1></div><div class=rpc-settings-item>端口<input type=text v-model=rpcSettings.port placeholder=6800></div><div class=rpc-settings-item>密钥<input type=text v-model=rpcSettings.secretKey></div><div class=rpc-settings-item>限速<input type=text v-model=rpcSettings.maxDownloadLimit placeholder=></div><div class=rpc-settings-item>路径<input type=text v-model=rpcSettings.dir></div><div class=rpc-settings-item>方法<v-dropdown style="text-transform: uppercase;"v-bind:items="['get', 'post']"v-bind:value.sync=rpcSettings.method></v-dropdown></div><div class="primary button"v-on:click="saveRpcSettings();toggleRpcSettings();exportData('aria2RPC')">确定</div></div></div></div></div></div>

File diff suppressed because one or more lines are too long

View File

@ -133,7 +133,7 @@ export const settings = {
port: '6800',
method: 'get',
skipByDefault: false,
maxDownloadLimit: '0',
maxDownloadLimit: '',
},
searchHistory: [],
seedsToCoins: true,

View File

@ -28,7 +28,7 @@ class Batch {
out: `${item.title}${indexNumber}.flv`,
split: fragmentSplitFactor,
dir: option.dir || undefined,
'max-download-limit': option.maxDownloadLimit,
'max-download-limit': option.maxDownloadLimit || undefined,
})
const id = encodeURIComponent(`${item.title}${indexNumber}`)
return {

View File

@ -92,10 +92,7 @@
密钥<input type="text" v-model="rpcSettings.secretKey">
</div>
<div class="rpc-settings-item">
单任务限速<input type="text" v-model="rpcSettings.maxDownloadLimit" placeholder="无">
</div>
<div class="rpc-settings-item">
总体限速<input type="text" v-model="rpcSettings.maxOverallDownloadLimit" placeholder="无">
限速<input type="text" v-model="rpcSettings.maxDownloadLimit" placeholder="无">
</div>
<div class="rpc-settings-item">
路径<input type="text" v-model="rpcSettings.dir">

View File

@ -301,7 +301,7 @@ class VideoDownloader {
out: `${getFriendlyTitle()}${indexNumber}${this.extension(fragment)}`,
split: this.fragmentSplitFactor,
dir: option.dir || undefined,
'max-download-limit': option.maxDownloadLimit,
'max-download-limit': option.maxDownloadLimit || undefined,
})
const id = encodeURIComponent(`${getFriendlyTitle()}${indexNumber}`)
return {