diff --git a/bilibili-evolved.offline.user.js b/bilibili-evolved.offline.user.js index 43b47b707..967795cca 100644 --- a/bilibili-evolved.offline.user.js +++ b/bilibili-evolved.offline.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name Bilibili Evolved (Offline) -// @version 176.21 +// @version 176.29 // @description 增强哔哩哔哩Web端体验(离线版): 修复界面瑕疵, 删除广告, 使用夜间模式浏览; 下载视频,封面,弹幕, 以及增加对触屏设备的支持等. // @author Grant Howard, Coulomb-G // @copyright 2018, Grant Howrad (https://github.com/the1812) @@ -1104,7 +1104,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/clear-cache.min.js"] = (()=>{return(n,c)=>{return{widget:{content:`\n \n \n 清除缓存\n `,condition:()=>typeof offlineData==="undefined",success:()=>{$("#clear-cache").on("click",()=>{n.cache={};saveSettings(n);Toast.success("已删除全部缓存.","清除缓存",5e3)})}}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(e,t)=>{const n={entity:null,aid:undefined,cid:undefined,isBangumi:false};const s=[];SpinQuery.unsafeJquery().then(()=>{unsafeWindow.$(unsafeWindow.document).ajaxSend((e,t,n)=>{if(n.url.indexOf("https://bangumi.bilibili.com/player/web_api/v2/playurl")!==-1){s.unshift(n.url)}})});class i{constructor(){this.menuPanel=document.querySelector(".download-video-panel");this.menuClasses=["quality","action","progress"];this.currentMenuClass="quality"}addMenuClass(){this.menuPanel.classList.remove(...this.menuClasses);this.menuPanel.classList.add(this.currentMenuClass);return this.currentMenuClass}resetMenuClass(){[this.currentMenuClass]=this.menuClasses;this.addMenuClass()}nextMenuClass(){const e=this.menuClasses.indexOf(this.currentMenuClass)+1;const t=this.menuClasses[e>=this.menuClasses.length?0:e];this.currentMenuClass=t;this.addMenuClass();return t}addError(){this.menuPanel.classList.add("error")}removeError(){this.menuPanel.classList.remove("error");this.resetMenuClass()}async getUrl(e){if(e){return`https://api.bilibili.com/x/player/playurl?avid=${n.aid}&cid=${n.cid}&qn=${e}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${n.aid}&cid=${n.cid}&otype=json`}}}class o extends i{constructor(e){super(e);this.menuClasses=["action","progress"];this.currentMenuClass="action"}async getUrl(){const e=await SpinQuery.select(()=>s[0]).catch(()=>logError("获取番剧下载链接失败."));return e}}class r{constructor(e,t,n){this.quality=e;this.internalName=t;this.displayName=n}async downloadInfo(){const e=new l(this);await e.fetchVideoInfo();return e}static get availableFormats(){return new Promise((e,t)=>{n.entity.getUrl().then(n=>{const s=new XMLHttpRequest;s.addEventListener("load",()=>{const n=JSON.parse(s.responseText);if(n.code!==0){t("获取清晰度信息失败.")}const i=n.data||n;const o=i.accept_quality;const a=i.accept_format.split(",");const l=i.accept_description;const c=[];while(o.length>0){const e=new r(o.pop(),a.pop(),l.pop());c.push(e)}e(c)});s.addEventListener("error",()=>t(`获取清晰度信息失败.`));s.withCredentials=true;s.open("GET",n);s.send()})})}}class a{constructor(e,t,n,s){this.length=e;this.size=t;this.url=n;this.backupUrls=s}}class l{constructor(e,t){this.format=e;this.fragments=t||[];this.progress=null;this.loaded=0;this.totalSize=null;this.workingXhr=null;this.fragmentSplitFactor=6*5}fetchVideoInfo(){return new Promise((e,t)=>{n.entity.getUrl(this.format.quality).then(s=>{const i=new XMLHttpRequest;i.addEventListener("load",()=>{const s=JSON.parse(i.responseText.replace(/http:/g,"https:"));const o=s.data||s;if(!n.isBangumi&&o.quality!==this.format.quality){t("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const r=o.durl;this.fragments=r.map(e=>new a(e.length,e.size,e.url,e.backup_url));e(this.fragments)});i.withCredentials=true;i.open("GET",s);i.send()})})}cancelDownload(){if("forEach"in this.workingXhr){this.workingXhr.forEach(e=>e.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(e){const t=[];this.workingXhr=[];const n=Math.round(e.size/this.fragmentSplitFactor);let s=0;while(s{let s=0;const o=new XMLHttpRequest;o.open("GET",e.url);o.responseType="arraybuffer";o.withCredentials=false;o.addEventListener("progress",e=>{this.loaded+=e.loaded-s;s=e.loaded;this.progress&&this.progress(this.loaded/this.totalSize)});o.addEventListener("load",()=>{if((""+o.status)[0]==="2"){t(o.response)}else{n(`请求失败.`)}});o.addEventListener("abort",()=>n("下载已取消."));o.addEventListener("error",()=>n(`下载失败.`));o.setRequestHeader("Range",i);o.send();this.workingXhr.push(o)}));s=Math.round(s+n)}return Promise.all(t)}copyUrl(){const e=this.fragments.map(e=>e.url).reduce((e,t)=>e+"\r\n"+t);GM_setClipboard(e,"text")}extension(e){return(e||this.fragments[0]).url.indexOf(".flv")!==-1?".flv":".mp4"}makeBlob(e,t=null){return new Blob(Array.isArray(e)?e:[e],{type:this.extension(t)===".flv"?"video/x-flv":"video/mp4"})}cleanUpOldBlobUrl(){const e=$("a#video-complete").attr("href");if(e&&$(`.link[href=${e}]`).length===0){URL.revokeObjectURL(e)}}downloadSingle(e){const[t]=e;const n=this.makeBlob(t);const s=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","")+this.extension();return[n,s]}async downloadMultiple(e){const t=new JSZip;const n=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","");if(e.length>1){e.forEach((e,s)=>{const i=this.fragments[s];t.file(`${n} - ${s+1}${this.extension(i)}`,this.makeBlob(e,i))})}else{const[s]=e;t.file(`${n}${this.extension()}`,this.makeBlob(s))}const s=await t.generateAsync({type:"blob"});const i=n+".zip";return[s,i]}async download(){const e=[];this.loaded=0;this.totalSize=this.fragments.map(e=>e.size).reduce((e,t)=>e+t);for(const t of this.fragments){const n=await this.downloadFragment(t);e.push(n)}if(e.length<1){throw new Error("下载失败.")}let t=null;let n=null;if(e.length===1){[t,n]=this.downloadSingle(e)}else{[t,n]=await this.downloadMultiple(e)}const s=URL.createObjectURL(t);this.cleanUpOldBlobUrl();this.progress&&this.progress(0);return{url:s,filename:n}}}async function c(){const e=await SpinQuery.select(()=>(unsafeWindow||window).aid);const t=await SpinQuery.select(()=>(unsafeWindow||window).cid);n.aid=e;n.cid=t;if(document.URL.indexOf("bangumi")!==-1){n.isBangumi=true;n.entity=new o}else{n.entity=new i}return e!==undefined&&t!==undefined}async function d(){await c();const e=await r.availableFormats;let[s]=e;const i=()=>s.downloadInfo().catch(e=>{n.entity.addError();$(".video-error").text(e)});async function o(){if(!s){return}n.entity.nextMenuClass();const e=await i();e.progress=(e=>{$(".download-progress-value").text(`${fixed(e*100)}`);$(".download-progress-foreground").css("transform",`scaleX(${e})`)});document.querySelector(".download-progress-cancel>span").onclick=(()=>e.cancelDownload());const t=await e.download().catch(e=>{n.entity.addError();$(".video-error").text(e)});if(!t){return}const o=document.getElementById("video-complete");o.setAttribute("href",t.url);o.setAttribute("download",t.filename);o.click();const r=`下载完成. 再次保存`;Toast.success(r,"下载视频");n.entity.resetMenuClass()}async function a(){if(!s){return}const e=await i();e.copyUrl();Toast.success("已复制链接到剪贴板.","复制链接",3e3);n.entity.resetMenuClass()}$(".video-action>#video-action-download").on("click",o);$(".video-action>#video-action-copy").on("click",a);e.forEach(e=>{$(`${e.displayName}`).on("click",()=>{s=e;n.entity.nextMenuClass()}).prependTo("ol.video-quality")});t.applyStyle("downloadVideoStyle");const l=document.querySelector(".download-video-panel");const d=()=>$(".download-video-panel").toggleClass("opened");$("#download-video").on("click",e=>{if(!l.contains(e.target)){d()}});$(".video-error").on("click",()=>{$(".video-error").text("");n.entity.removeError()});n.entity.addMenuClass()}return{widget:{content:t.data.downloadVideoDom.text,condition:c,success:d}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-danmaku.min.js"] = (()=>{return(n,t)=>{const{DanmakuInfo:e}=t.import("videoInfo");const{DanmakuConverter:o,XmlDanmakuDocument:a}=t.import("danmakuConverter");async function i(n){const t=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","");const i=new e((unsafeWindow||window).cid);await i.fetchInfo();const c=new o({title:t,font:"Microsoft YaHei UI",alpha:.6,duration:5,blockTypes:[],resolution:{x:1920,y:1080}});const d=c.convertToAssDocument(new a(i.rawXML));const s=new Blob([d.generateAss()],{type:"text/plain"});const u=URL.createObjectURL(s);const r=$("#danmaku-link");const l=r.attr("href");if(l){URL.revokeObjectURL(l)}clearTimeout(n);document.querySelector("#download-danmaku>span").innerHTML="下载弹幕";r.attr("download",`${t}.ass`).attr("href",u).get(0).click()}return{widget:{content:`\n \n \n 下载弹幕\n \n `,condition:async()=>{let n=await SpinQuery.condition(()=>(unsafeWindow||window).cid,n=>n!==undefined);return n!==undefined},success:()=>{const n=document.querySelector("#danmaku-link");$("#download-danmaku").on("click",t=>{if(t.target!==n){const n=setTimeout(()=>document.querySelector("#download-danmaku>span").innerHTML="请稍侯...",200);i(n)}})}}}}})(); -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/danmaku-converter.min.js"] = (()=>{return(t,e)=>{class i{constructor(t,e,i,n,s){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(n);this.color=parseInt(s)}}class n extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,n,s);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,n,s,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,s,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new n({content:u,time:i,type:s,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class s{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>n.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,n,s);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:n,resolution:s}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=n;this.resolution=s}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const n=e*2;const s=this.duration*n/(this.resolution.x+n)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:n,start:t.time,visible:t.time+s,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let n=null;let s=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==s){return false}return e.end>t.time};do{n=this.verticalTrack.find(a);s+=o}while(n&&s<=this.trackCount&&s>=0);if(s>this.trackCount||s<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:s});if(i){return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const n={tags:e};i.push(n);return n}}class h{constructor({title:t,font:e,alpha:i,duration:n,blockTypes:s,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=n;this.blockTypes=s;this.resolution=o;this.danmakuStack=new r(e,o,n)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,n]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:n,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const n=i.substring(4,6);const s=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${s}${n}&`}convertTime(t,e){function i(t){return String(Math.round(t*100)/100).padStart(5,"0")}function n(t){let e=0;let n=0;while(t>=60){t-=60;n++}while(n>=60){n-=60;e++}return`${e}:${String(n).padStart(2,"0")}:${i(t)}`}return[n(t),n(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:n,XmlDanmakuDocument:s}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/danmaku-converter.min.js"] = (()=>{return(t,e)=>{class i{constructor(t,e,i,s,n){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(s);this.color=parseInt(n)}}class s extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,s,n);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,s,n,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,n,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new s({content:u,time:i,type:n,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class n{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>s.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,s,n);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:s,resolution:n}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=s;this.resolution=n}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const s=e*2;const n=this.duration*s/(this.resolution.x+s)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:s,start:t.time,visible:t.time+n,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let s=null;let n=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==n){return false}return e.end>t.time};do{s=this.verticalTrack.find(a);n+=o}while(s&&n<=this.trackCount&&n>=0);if(n>this.trackCount||n<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:n});if(i){return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const s={tags:e};i.push(s);return s}}class h{constructor({title:t,font:e,alpha:i,duration:s,blockTypes:n,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=s;this.blockTypes=n;this.resolution=o;this.danmakuStack=new r(e,o,s)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,s]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:s,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const s=i.substring(4,6);const n=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${n}${s}&`}convertTime(t,e){function i(t){const[e,i="00"]=String(t).split(".");return`${e.padStart(2,"0")}.${i.substr(0,2).padRight(2,"0")}`}function s(t){let e=0;let s=0;while(t>=60){t-=60;s++}while(s>=60){s-=60;e++}return`${e}:${String(s).padStart(2,"0")}:${i(t)}`}return[s(t),s(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:s,XmlDanmakuDocument:n}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/video-info.min.js"] = (()=>{return()=>{class t{constructor(t){this.aid=t}async fetchInfo(){const t=JSON.parse(await downloadText(`https://api.bilibili.com/x/web-interface/view?aid=${this.aid}`));if(t.code!==0){throw new Error(t.message)}const i=t.data;this.cid=i.cid;this.pageCount=i.videos;this.coverUrl=i.pic;this.tagId=i.tid;this.tagName=i.tname;this.title=i.title;this.description=i.desc;this.up={uid:i.owner.mid,name:i.owner.name,faceUrl:i.owner.face};this.pages=i.pages.map(t=>{return{cid:t.cid,title:t.part,pageNumber:t.page}});return this}async fetchDanmaku(){this.danmaku=new e(this.cid);return this.danmaku.fetchInfo()}}class i{constructor(t,i){this.text=t;this.p=i}}class e{constructor(t){this.cid=t}async fetchInfo(){const t=await downloadText(`https://api.bilibili.com/x/v1/dm/list.so?oid=${this.cid}`);this.rawXML=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.xml=e;this.danmakus=[].map.call(e.querySelectorAll("d[p]"),t=>{return new i(t.innerHTML,t.getAttribute("p"))})}}class a{constructor(t){this.ep=t;this.videos=[]}async fetchInfo(){const i=await downloadText(`https://www.bilibili.com/bangumi/play/ep${this.ep}/`);const e=JSON.parse(i.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){/)[1]);this.title=e.mediaInfo.title;this.cover=e.mediaInfo.cover;this.squareCover=e.mediaInfo.square_cover;this.aid=e.epInfo.aid;this.cid=e.epInfo.cid;this.videos=e.epList.map(async i=>{return{title:i.index_title,aid:i.aid,cid:i.cid,info:await new t(i.aid).fetchInfo()}});return this}}return{export:{VideoInfo:t,BangumiInfo:a,Danmaku:i,DanmakuInfo:e}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.html"] = `Bilibili Evolved作者:Grant Howard,Coulomb-G网站:GitHub开源组件关闭`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.css"] = `.about.gui-settings-footer{height:24px;font-size:14px;justify-content:space-between;padding:6px 24px;border-top:1px dashed #8884;}.about.gui-settings-footer>span{opacity:0.2;}.bilibili-evolved-about{display:flex;width:400px;height:70vh;background-color:white;position:fixed;top:15%;left:calc(50% - 200px);z-index:100000;box-shadow:0px 3px 20px 2px #0004;border-top:4px solid var(--theme-color);flex-direction:column;transition:all .2s ease-out;transform-origin:center;transform:scale(0);}.bilibili-evolved-about.opened{transform:scale(1);}.bilibili-evolved-info a{margin:0 4px;}.bilibili-evolved-info>p{margin:8px 0;}.bilibili-evolved-about>div{flex:1 0 0;display:flex;align-items:center;justify-content:space-between;flex-direction:column;padding:8px;}.bilibili-evolved-about>div.about-block{flex:4 0 0;padding:32px;align-items:stretch;}.bilibili-evolved-about h1{font-size:36px;margin-bottom:16px;}.bilibili-evolved-about h2{font-size:18px;margin-bottom:8px;}.open-source-components>li{margin:12px 0;padding:12px 24px;background:rgba(0,0,0,0.2);border-left:4px solid var(--theme-color);cursor:pointer;transition:all .2s ease-out;}.open-source-components>li:hover{opacity:0.8;}.component-name{font-size:18px;font-weight:bold;}.component-info{margin-top:8px;}#about-link{cursor:pointer;transition:all .2s;}.bilibili-evolved-about a{color:var(--theme-color);}#about-link:hover{opacity:1;color:var(--theme-color);}#about-close{background-color:#8884;border-color:transparent;opacity:1;transition:all .2s ease-out;width:80px;height:32px;color:inherit;cursor:pointer;}#about-close:hover{opacity:0.8;}#about-close:active{outline:none;opacity:0.6;}`; diff --git a/bilibili-evolved.preview-offline.user.js b/bilibili-evolved.preview-offline.user.js index 2f0aebd6a..3b27a33d7 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 176.21 +// @version 176.29 // @description 增强哔哩哔哩Web端体验(预览离线版): 修复界面瑕疵, 删除广告, 使用夜间模式浏览; 下载视频,封面,弹幕, 以及增加对触屏设备的支持等. // @author Grant Howard, Coulomb-G // @copyright 2018, Grant Howrad (https://github.com/the1812) @@ -1104,7 +1104,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/clear-cache.min.js"] = (()=>{return(n,c)=>{return{widget:{content:`\n \n \n 清除缓存\n `,condition:()=>typeof offlineData==="undefined",success:()=>{$("#clear-cache").on("click",()=>{n.cache={};saveSettings(n);Toast.success("已删除全部缓存.","清除缓存",5e3)})}}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-video.min.js"] = (()=>{return(e,t)=>{const n={entity:null,aid:undefined,cid:undefined,isBangumi:false};const s=[];SpinQuery.unsafeJquery().then(()=>{unsafeWindow.$(unsafeWindow.document).ajaxSend((e,t,n)=>{if(n.url.indexOf("https://bangumi.bilibili.com/player/web_api/v2/playurl")!==-1){s.unshift(n.url)}})});class i{constructor(){this.menuPanel=document.querySelector(".download-video-panel");this.menuClasses=["quality","action","progress"];this.currentMenuClass="quality"}addMenuClass(){this.menuPanel.classList.remove(...this.menuClasses);this.menuPanel.classList.add(this.currentMenuClass);return this.currentMenuClass}resetMenuClass(){[this.currentMenuClass]=this.menuClasses;this.addMenuClass()}nextMenuClass(){const e=this.menuClasses.indexOf(this.currentMenuClass)+1;const t=this.menuClasses[e>=this.menuClasses.length?0:e];this.currentMenuClass=t;this.addMenuClass();return t}addError(){this.menuPanel.classList.add("error")}removeError(){this.menuPanel.classList.remove("error");this.resetMenuClass()}async getUrl(e){if(e){return`https://api.bilibili.com/x/player/playurl?avid=${n.aid}&cid=${n.cid}&qn=${e}&otype=json`}else{return`https://api.bilibili.com/x/player/playurl?avid=${n.aid}&cid=${n.cid}&otype=json`}}}class o extends i{constructor(e){super(e);this.menuClasses=["action","progress"];this.currentMenuClass="action"}async getUrl(){const e=await SpinQuery.select(()=>s[0]).catch(()=>logError("获取番剧下载链接失败."));return e}}class r{constructor(e,t,n){this.quality=e;this.internalName=t;this.displayName=n}async downloadInfo(){const e=new l(this);await e.fetchVideoInfo();return e}static get availableFormats(){return new Promise((e,t)=>{n.entity.getUrl().then(n=>{const s=new XMLHttpRequest;s.addEventListener("load",()=>{const n=JSON.parse(s.responseText);if(n.code!==0){t("获取清晰度信息失败.")}const i=n.data||n;const o=i.accept_quality;const a=i.accept_format.split(",");const l=i.accept_description;const c=[];while(o.length>0){const e=new r(o.pop(),a.pop(),l.pop());c.push(e)}e(c)});s.addEventListener("error",()=>t(`获取清晰度信息失败.`));s.withCredentials=true;s.open("GET",n);s.send()})})}}class a{constructor(e,t,n,s){this.length=e;this.size=t;this.url=n;this.backupUrls=s}}class l{constructor(e,t){this.format=e;this.fragments=t||[];this.progress=null;this.loaded=0;this.totalSize=null;this.workingXhr=null;this.fragmentSplitFactor=6*5}fetchVideoInfo(){return new Promise((e,t)=>{n.entity.getUrl(this.format.quality).then(s=>{const i=new XMLHttpRequest;i.addEventListener("load",()=>{const s=JSON.parse(i.responseText.replace(/http:/g,"https:"));const o=s.data||s;if(!n.isBangumi&&o.quality!==this.format.quality){t("获取下载链接失败, 请确认当前账号有下载权限后重试.")}const r=o.durl;this.fragments=r.map(e=>new a(e.length,e.size,e.url,e.backup_url));e(this.fragments)});i.withCredentials=true;i.open("GET",s);i.send()})})}cancelDownload(){if("forEach"in this.workingXhr){this.workingXhr.forEach(e=>e.abort())}else{logError("Cancel Download Failed: forEach in this.workingXhr not found.")}}downloadFragment(e){const t=[];this.workingXhr=[];const n=Math.round(e.size/this.fragmentSplitFactor);let s=0;while(s{let s=0;const o=new XMLHttpRequest;o.open("GET",e.url);o.responseType="arraybuffer";o.withCredentials=false;o.addEventListener("progress",e=>{this.loaded+=e.loaded-s;s=e.loaded;this.progress&&this.progress(this.loaded/this.totalSize)});o.addEventListener("load",()=>{if((""+o.status)[0]==="2"){t(o.response)}else{n(`请求失败.`)}});o.addEventListener("abort",()=>n("下载已取消."));o.addEventListener("error",()=>n(`下载失败.`));o.setRequestHeader("Range",i);o.send();this.workingXhr.push(o)}));s=Math.round(s+n)}return Promise.all(t)}copyUrl(){const e=this.fragments.map(e=>e.url).reduce((e,t)=>e+"\r\n"+t);GM_setClipboard(e,"text")}extension(e){return(e||this.fragments[0]).url.indexOf(".flv")!==-1?".flv":".mp4"}makeBlob(e,t=null){return new Blob(Array.isArray(e)?e:[e],{type:this.extension(t)===".flv"?"video/x-flv":"video/mp4"})}cleanUpOldBlobUrl(){const e=$("a#video-complete").attr("href");if(e&&$(`.link[href=${e}]`).length===0){URL.revokeObjectURL(e)}}downloadSingle(e){const[t]=e;const n=this.makeBlob(t);const s=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","")+this.extension();return[n,s]}async downloadMultiple(e){const t=new JSZip;const n=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","");if(e.length>1){e.forEach((e,s)=>{const i=this.fragments[s];t.file(`${n} - ${s+1}${this.extension(i)}`,this.makeBlob(e,i))})}else{const[s]=e;t.file(`${n}${this.extension()}`,this.makeBlob(s))}const s=await t.generateAsync({type:"blob"});const i=n+".zip";return[s,i]}async download(){const e=[];this.loaded=0;this.totalSize=this.fragments.map(e=>e.size).reduce((e,t)=>e+t);for(const t of this.fragments){const n=await this.downloadFragment(t);e.push(n)}if(e.length<1){throw new Error("下载失败.")}let t=null;let n=null;if(e.length===1){[t,n]=this.downloadSingle(e)}else{[t,n]=await this.downloadMultiple(e)}const s=URL.createObjectURL(t);this.cleanUpOldBlobUrl();this.progress&&this.progress(0);return{url:s,filename:n}}}async function c(){const e=await SpinQuery.select(()=>(unsafeWindow||window).aid);const t=await SpinQuery.select(()=>(unsafeWindow||window).cid);n.aid=e;n.cid=t;if(document.URL.indexOf("bangumi")!==-1){n.isBangumi=true;n.entity=new o}else{n.entity=new i}return e!==undefined&&t!==undefined}async function d(){await c();const e=await r.availableFormats;let[s]=e;const i=()=>s.downloadInfo().catch(e=>{n.entity.addError();$(".video-error").text(e)});async function o(){if(!s){return}n.entity.nextMenuClass();const e=await i();e.progress=(e=>{$(".download-progress-value").text(`${fixed(e*100)}`);$(".download-progress-foreground").css("transform",`scaleX(${e})`)});document.querySelector(".download-progress-cancel>span").onclick=(()=>e.cancelDownload());const t=await e.download().catch(e=>{n.entity.addError();$(".video-error").text(e)});if(!t){return}const o=document.getElementById("video-complete");o.setAttribute("href",t.url);o.setAttribute("download",t.filename);o.click();const r=`下载完成. 再次保存`;Toast.success(r,"下载视频");n.entity.resetMenuClass()}async function a(){if(!s){return}const e=await i();e.copyUrl();Toast.success("已复制链接到剪贴板.","复制链接",3e3);n.entity.resetMenuClass()}$(".video-action>#video-action-download").on("click",o);$(".video-action>#video-action-copy").on("click",a);e.forEach(e=>{$(`${e.displayName}`).on("click",()=>{s=e;n.entity.nextMenuClass()}).prependTo("ol.video-quality")});t.applyStyle("downloadVideoStyle");const l=document.querySelector(".download-video-panel");const d=()=>$(".download-video-panel").toggleClass("opened");$("#download-video").on("click",e=>{if(!l.contains(e.target)){d()}});$(".video-error").on("click",()=>{$(".video-error").text("");n.entity.removeError()});n.entity.addMenuClass()}return{widget:{content:t.data.downloadVideoDom.text,condition:c,success:d}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/download-danmaku.min.js"] = (()=>{return(n,t)=>{const{DanmakuInfo:e}=t.import("videoInfo");const{DanmakuConverter:o,XmlDanmakuDocument:a}=t.import("danmakuConverter");async function i(n){const t=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","").replace("_番剧_bilibili_哔哩哔哩","");const i=new e((unsafeWindow||window).cid);await i.fetchInfo();const c=new o({title:t,font:"Microsoft YaHei UI",alpha:.6,duration:5,blockTypes:[],resolution:{x:1920,y:1080}});const d=c.convertToAssDocument(new a(i.rawXML));const s=new Blob([d.generateAss()],{type:"text/plain"});const u=URL.createObjectURL(s);const r=$("#danmaku-link");const l=r.attr("href");if(l){URL.revokeObjectURL(l)}clearTimeout(n);document.querySelector("#download-danmaku>span").innerHTML="下载弹幕";r.attr("download",`${t}.ass`).attr("href",u).get(0).click()}return{widget:{content:`\n \n \n 下载弹幕\n \n `,condition:async()=>{let n=await SpinQuery.condition(()=>(unsafeWindow||window).cid,n=>n!==undefined);return n!==undefined},success:()=>{const n=document.querySelector("#danmaku-link");$("#download-danmaku").on("click",t=>{if(t.target!==n){const n=setTimeout(()=>document.querySelector("#download-danmaku>span").innerHTML="请稍侯...",200);i(n)}})}}}}})(); -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/danmaku-converter.min.js"] = (()=>{return(t,e)=>{class i{constructor(t,e,i,n,s){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(n);this.color=parseInt(s)}}class n extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,n,s);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,n,s,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,s,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new n({content:u,time:i,type:s,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class s{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>n.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,n,s);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:n,resolution:s}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=n;this.resolution=s}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const n=e*2;const s=this.duration*n/(this.resolution.x+n)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:n,start:t.time,visible:t.time+s,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let n=null;let s=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==s){return false}return e.end>t.time};do{n=this.verticalTrack.find(a);s+=o}while(n&&s<=this.trackCount&&s>=0);if(s>this.trackCount||s<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:s});if(i){return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const n={tags:e};i.push(n);return n}}class h{constructor({title:t,font:e,alpha:i,duration:n,blockTypes:s,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=n;this.blockTypes=s;this.resolution=o;this.danmakuStack=new r(e,o,n)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,n]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:n,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const n=i.substring(4,6);const s=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${s}${n}&`}convertTime(t,e){function i(t){return String(Math.round(t*100)/100).padStart(5,"0")}function n(t){let e=0;let n=0;while(t>=60){t-=60;n++}while(n>=60){n-=60;e++}return`${e}:${String(n).padStart(2,"0")}:${i(t)}`}return[n(t),n(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:n,XmlDanmakuDocument:s}}}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/danmaku-converter.min.js"] = (()=>{return(t,e)=>{class i{constructor(t,e,i,s,n){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(s);this.color=parseInt(n)}}class s extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,s,n);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,s,n,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,n,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new s({content:u,time:i,type:n,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class n{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>s.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,s,n);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:s,resolution:n}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=s;this.resolution=n}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const s=e*2;const n=this.duration*s/(this.resolution.x+s)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:s,start:t.time,visible:t.time+n,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let s=null;let n=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==n){return false}return e.end>t.time};do{s=this.verticalTrack.find(a);n+=o}while(s&&n<=this.trackCount&&n>=0);if(n>this.trackCount||n<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:n});if(i){return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const s={tags:e};i.push(s);return s}}class h{constructor({title:t,font:e,alpha:i,duration:s,blockTypes:n,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=s;this.blockTypes=n;this.resolution=o;this.danmakuStack=new r(e,o,s)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,s]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:s,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const s=i.substring(4,6);const n=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${n}${s}&`}convertTime(t,e){function i(t){const[e,i="00"]=String(t).split(".");return`${e.padStart(2,"0")}.${i.substr(0,2).padRight(2,"0")}`}function s(t){let e=0;let s=0;while(t>=60){t-=60;s++}while(s>=60){s-=60;e++}return`${e}:${String(s).padStart(2,"0")}:${i(t)}`}return[s(t),s(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:s,XmlDanmakuDocument:n}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/video-info.min.js"] = (()=>{return()=>{class t{constructor(t){this.aid=t}async fetchInfo(){const t=JSON.parse(await downloadText(`https://api.bilibili.com/x/web-interface/view?aid=${this.aid}`));if(t.code!==0){throw new Error(t.message)}const i=t.data;this.cid=i.cid;this.pageCount=i.videos;this.coverUrl=i.pic;this.tagId=i.tid;this.tagName=i.tname;this.title=i.title;this.description=i.desc;this.up={uid:i.owner.mid,name:i.owner.name,faceUrl:i.owner.face};this.pages=i.pages.map(t=>{return{cid:t.cid,title:t.part,pageNumber:t.page}});return this}async fetchDanmaku(){this.danmaku=new e(this.cid);return this.danmaku.fetchInfo()}}class i{constructor(t,i){this.text=t;this.p=i}}class e{constructor(t){this.cid=t}async fetchInfo(){const t=await downloadText(`https://api.bilibili.com/x/v1/dm/list.so?oid=${this.cid}`);this.rawXML=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.xml=e;this.danmakus=[].map.call(e.querySelectorAll("d[p]"),t=>{return new i(t.innerHTML,t.getAttribute("p"))})}}class a{constructor(t){this.ep=t;this.videos=[]}async fetchInfo(){const i=await downloadText(`https://www.bilibili.com/bangumi/play/ep${this.ep}/`);const e=JSON.parse(i.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){/)[1]);this.title=e.mediaInfo.title;this.cover=e.mediaInfo.cover;this.squareCover=e.mediaInfo.square_cover;this.aid=e.epInfo.aid;this.cid=e.epInfo.cid;this.videos=e.epList.map(async i=>{return{title:i.index_title,aid:i.aid,cid:i.cid,info:await new t(i.aid).fetchInfo()}});return this}}return{export:{VideoInfo:t,BangumiInfo:a,Danmaku:i,DanmakuInfo:e}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.html"] = `Bilibili Evolved作者:Grant Howard,Coulomb-G网站:GitHub开源组件关闭`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.css"] = `.about.gui-settings-footer{height:24px;font-size:14px;justify-content:space-between;padding:6px 24px;border-top:1px dashed #8884;}.about.gui-settings-footer>span{opacity:0.2;}.bilibili-evolved-about{display:flex;width:400px;height:70vh;background-color:white;position:fixed;top:15%;left:calc(50% - 200px);z-index:100000;box-shadow:0px 3px 20px 2px #0004;border-top:4px solid var(--theme-color);flex-direction:column;transition:all .2s ease-out;transform-origin:center;transform:scale(0);}.bilibili-evolved-about.opened{transform:scale(1);}.bilibili-evolved-info a{margin:0 4px;}.bilibili-evolved-info>p{margin:8px 0;}.bilibili-evolved-about>div{flex:1 0 0;display:flex;align-items:center;justify-content:space-between;flex-direction:column;padding:8px;}.bilibili-evolved-about>div.about-block{flex:4 0 0;padding:32px;align-items:stretch;}.bilibili-evolved-about h1{font-size:36px;margin-bottom:16px;}.bilibili-evolved-about h2{font-size:18px;margin-bottom:8px;}.open-source-components>li{margin:12px 0;padding:12px 24px;background:rgba(0,0,0,0.2);border-left:4px solid var(--theme-color);cursor:pointer;transition:all .2s ease-out;}.open-source-components>li:hover{opacity:0.8;}.component-name{font-size:18px;font-weight:bold;}.component-info{margin-top:8px;}#about-link{cursor:pointer;transition:all .2s;}.bilibili-evolved-about a{color:var(--theme-color);}#about-link:hover{opacity:1;color:var(--theme-color);}#about-close{background-color:#8884;border-color:transparent;opacity:1;transition:all .2s ease-out;width:80px;height:32px;color:inherit;cursor:pointer;}#about-close:hover{opacity:0.8;}#about-close:active{outline:none;opacity:0.6;}`; diff --git a/min/danmaku-converter.min.js b/min/danmaku-converter.min.js index 0bbcb7d01..f5d05b6c2 100644 --- a/min/danmaku-converter.min.js +++ b/min/danmaku-converter.min.js @@ -1 +1 @@ -(()=>{return(t,e)=>{class i{constructor(t,e,i,n,s){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(n);this.color=parseInt(s)}}class n extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,n,s);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,n,s,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,s,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new n({content:u,time:i,type:s,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class s{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>n.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:n,color:s,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,n,s);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:n,resolution:s}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=n;this.resolution=s}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const n=e*2;const s=this.duration*n/(this.resolution.x+n)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:n,start:t.time,visible:t.time+s,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let n=null;let s=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==s){return false}return e.end>t.time};do{n=this.verticalTrack.find(a);s+=o}while(n&&s<=this.trackCount&&s>=0);if(s>this.trackCount||s<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:s});if(i){return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${s*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const n={tags:e};i.push(n);return n}}class h{constructor({title:t,font:e,alpha:i,duration:n,blockTypes:s,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=n;this.blockTypes=s;this.resolution=o;this.danmakuStack=new r(e,o,n)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,n]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:n,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const n=i.substring(4,6);const s=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${s}${n}&`}convertTime(t,e){function i(t){return String(Math.round(t*100)/100).padStart(5,"0")}function n(t){let e=0;let n=0;while(t>=60){t-=60;n++}while(n>=60){n-=60;e++}return`${e}:${String(n).padStart(2,"0")}:${i(t)}`}return[n(t),n(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:n,XmlDanmakuDocument:s}}}})(); \ No newline at end of file +(()=>{return(t,e)=>{class i{constructor(t,e,i,s,n){this.content=t;this.time=e;this.type=parseInt(i);this.fontSize=parseFloat(s);this.color=parseInt(n)}}class s extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,timeStamp:o,pool:a,userHash:r,rowId:h}){super(t,e,i,s,n);this.timeStamp=parseInt(o);this.pool=parseInt(a);this.userHash=r;this.rowId=parseInt(h);this.time=parseFloat(this.time);this.pDataArray=[e,i,s,n,o,a,r,h]}text(){const t=this.pDataArray.join(",");return`${this.content}`}static parse(t){const e=t.getAttribute("p");const[i,n,o,a,r,h,l,c]=e.split(",");const u=t.innerHTML;return new s({content:u,time:i,type:n,fontSize:o,color:a,timeStamp:r,pool:h,userHash:l,rowId:c})}}class n{constructor(t){this.xml=t;const e=(new DOMParser).parseFromString(t,"application/xml").documentElement;this.danmakus=[...e.querySelectorAll("d[p]")].map(t=>s.parse(t))}}class o extends i{constructor({content:t,time:e,type:i,fontSize:s,color:n,typeTag:o,colorTag:a,endTime:r}){super(t,e,i,s,n);this.typeTag=o;this.colorTag=a;this.endTime=r}text(t){const e=t[this.fontSize].match(/Style:(.*?),/)[1].trim();return`Dialogue: 0,${this.time},${this.endTime},${e},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`}}class a{constructor({danmakus:t,title:e,fontStyles:i,blockTypes:s,resolution:n}){this.danmakus=t;this.title=e;this.fontStyles=i;this.blockTypes=s;this.resolution=n}generateAss(){const t=`\n[Script Info]\n; Script generated by Bilibili Evolved Danmaku Converter\n; https://github.com/the1812/Bilibili-Evolved/\nTitle: ${this.title}\nScriptType: v4.00+\nPlayResX: ${this.resolution.x}\nPlayResY: ${this.resolution.y}\nTimer: 10.0000\nWrapStyle: 2\nScaledBorderAndShadow: no\n\n[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n${Object.values(this.fontStyles).join("\n")}\n\n[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n `.trim();return t+"\n"+this.danmakus.map(t=>t.text(this.fontStyles,this.blockTypes)).filter(t=>t!=="").join("\n")}}class r{constructor(t,e,i){this.horizontalDanmakus=[];this.horizontalTrack=[];this.verticalDanmakus=[];this.verticalTrack=[];this.resolution=e;this.duration=i;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`52px ${t}`,18:`36px ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"};this.margin=10;this.nextDanmakuDelay=.1;this.generateTracks()}generateTracks(){this.context.font=this.fontSizes[25];const t=this.context.measureText("Lorem ipsum");const e=t.emHeightAscent+t.emHeightDescent;this.danmakuHeight=e;this.trackHeight=this.margin*2+e;this.trackCount=parseInt(fixed(this.resolution.y/this.trackHeight,0))}getTextSize(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const i=e.width/2;return[i,this.danmakuHeight/2]}getHorizonalTags(t){const[e,i]=this.getTextSize(t);const s=e*2;const n=this.duration*s/(this.resolution.x+s)+this.nextDanmakuDelay;let o=0;let a=null;const r=e=>{if(e.track!==o){return false}if(e.widtht.time}else{return e.visible>t.time}};do{a=this.horizontalTrack.find(r);o++}while(a&&o<=this.trackCount);if(o>this.trackCount){return`\\alpha&HFF`}o--;this.horizontalTrack.push({width:s,start:t.time,visible:t.time+n,end:t.time+this.duration,track:o});return`\\move(${this.resolution.x+e}, ${o*this.trackHeight+this.margin+i}, ${-e}, ${o*this.trackHeight+this.margin+i}, 0, ${this.duration*1e3})`}getVerticalTags(t){const[,e]=this.getTextSize(t);const i=this.danmakuType[t.type]==="top";let s=null;let n=i?0:this.trackCount-1;const o=i?1:-1;const a=e=>{if(e.track!==n){return false}return e.end>t.time};do{s=this.verticalTrack.find(a);n+=o}while(s&&n<=this.trackCount&&n>=0);if(n>this.trackCount||n<0){return`\\alpha&HFF`}this.verticalTrack.push({start:t.time,end:t.time+this.duration,track:n});if(i){return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.margin+e})`}else{return`\\pos(${this.resolution.x/2}, ${n*this.trackHeight+this.resolution.y-this.margin-e})`}}push(t){let e=null;let i=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);i=this.horizontalDanmakus;break}case"top":case"bottom":{e=this.getVerticalTags(t);i=this.verticalDanmakus;break}case"special":default:{throw new Error("Danmaku type not supported")}}const s={tags:e};i.push(s);return s}}class h{constructor({title:t,font:e,alpha:i,duration:s,blockTypes:n,resolution:o}){this.title=t;this.font=e;this.alpha=Math.round(i*100);this.duration=s;this.blockTypes=n;this.resolution=o;this.danmakuStack=new r(e,o,s)}get fontStyles(){return{25:`Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`,18:`Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,0,0,0,0,100,100,0,0,1,1,0,5,0,0,0,0`}}convertToAssDocument(t){const e=[];for(const i of t.danmakus.sort((t,e)=>t.time-e.time)){if(this.blockTypes.concat(7,8).indexOf(i.type)!==-1){continue}const[t,s]=this.convertTime(i.time,this.duration);e.push(new o({content:i.content,time:t,endTime:s,type:i.type,fontSize:i.fontSize,color:i.color,typeTag:this.convertType(i),colorTag:this.convertColor(i.color)}))}return new a({danmakus:e,title:this.title,blockTypes:this.blockTypes,fontStyles:this.fontStyles,resolution:this.resolution})}convertType(t){return this.danmakuStack.push(t).tags}convertColor(t){const e=16777215;if(t===e){return""}const i=t.toString(16);const s=i.substring(4,6);const n=i.substring(2,4);const o=i.substring(0,2);return`\\c&H${o}${n}${s}&`}convertTime(t,e){function i(t){const[e,i="00"]=String(t).split(".");return`${e.padStart(2,"0")}.${i.substr(0,2).padRight(2,"0")}`}function s(t){let e=0;let s=0;while(t>=60){t-=60;s++}while(s>=60){s-=60;e++}return`${e}:${String(s).padStart(2,"0")}:${i(t)}`}return[s(t),s(t+e)]}}return{export:{AssDanmaku:o,AssDanmakuDocument:a,Danmaku:i,DanmakuConverter:h,DanmakuStack:r,XmlDanmaku:s,XmlDanmakuDocument:n}}}})(); \ No newline at end of file diff --git a/video/danmaku-converter/danmaku-converter.js b/video/danmaku-converter/danmaku-converter.js index d1c475c50..404d5b3d3 100644 --- a/video/danmaku-converter/danmaku-converter.js +++ b/video/danmaku-converter/danmaku-converter.js @@ -336,7 +336,8 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text { function round(number) { - return String(Math.round(number * 100) / 100).padStart(5, "0"); + const [integer, decimal = "00"] = String(number).split("."); + return `${integer.padStart(2, "0")}.${decimal.substr(0, 2).padRight(2, "0")}`; } function secondsToTime(seconds) {
作者:Grant Howard,Coulomb-G
网站:GitHub