Add metrics

This commit is contained in:
the1812 2019-01-07 21:15:56 +08:00
parent 1dffee0af0
commit 7a13b81305
6 changed files with 32 additions and 12 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

@ -1 +1 @@
(()=>{return(t,e)=>{class n{constructor(t,e,n,s,o){this.content=t;this.time=e;this.type=n;this.fontSize=s;this.color=o}}class s extends n{constructor({content:t,time:e,type:n,fontSize:s,color:o,timeStamp:i,pool:a,userHash:r,rowId:l}){super(t,e,n,s,o);this.timeStamp=i;this.pool=a;this.userHash=r;this.rowId=l;this.pDataArray=[e,n,s,o,i,a,r,l]}text(){const t=this.pDataArray.join(",");return`<d p="${t}">${this.content}</d>`}static parse(t){const e=t.getAttribute("p");const[n,o,i,a,r,l,c,h]=e.split(",");const u=t.innerHTML;return new s({content:u,time:n,type:o,fontSize:i,color:a,timeStamp:r,pool:l,userHash:c,rowId:h})}}class o{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 i extends n{constructor({content:t,time:e,type:n,fontSize:s,color:o,typeTag:i,colorTag:a,endTime:r}){super(t,e,n,s,o);this.typeTag=i;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:n,blockTypes:s,resolution:o}){this.danmakus=t;this.title=e;this.fontStyles=n;this.blockTypes=s;this.resolution=o}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){this.horizontal=[];this.vertical=[];this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`36pt ${t}`,18:`26pt ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"}}getHorizonalTags(t){return`\\pos(960, 540)`}getVerticalTags(t){return`\\pos(960, 540)`}push(t){let e=null;let n=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);n=this.horizontal;break}case"top":case"bottom":{e=this.getVerticalTags(t);n=this.vertical;break}case"special":default:{throw new Error("Danmaku type not supported")}}const s={tags:e};n.push(s);return s}}class l{constructor({title:t,font:e,alpha:n,duration:s,blockTypes:o,resolution:i}){this.title=t;this.font=e;this.alpha=Math.round(n*100);this.duration=s;this.blockTypes=o;this.resolution=i;this.danmakuStack=new r(e,i)}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 n of t.danmakus){if(this.blockTypes.concat(7,8).indexOf(n.type)!==-1){continue}const[t,s]=this.convertTime(parseFloat(n.time),this.duration);e.push(new i({content:n.content,time:t,endTime:s,type:n.type,fontSize:n.fontSize,color:n.color,typeTag:this.convertType(n),colorTag:this.convertColor(parseInt(n.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 n=t.toString(16);const s=n.substring(4,6);const o=n.substring(2,4);const i=n.substring(0,2);return`\\c&H${i}${o}${s}&`}convertTime(t,e){function n(t){return Math.round(t*100)/100}function s(t){let e=0;let s=0;while(t>=60){t-=60;s++}while(s>=60){s-=60;e++}return`${e}:${s.toString().padStart(2,"0")}:${n(t).toString().padStart(4,"0")}`}return[s(t),s(t+e)]}}return{export:{AssDanmaku:i,AssDanmakuDocument:a,Danmaku:n,DanmakuConverter:l,DanmakuStack:r,XmlDanmaku:s,XmlDanmakuDocument:o}}}})();
(()=>{return(t,e)=>{class n{constructor(t,e,n,s,o){this.content=t;this.time=e;this.type=n;this.fontSize=s;this.color=o}}class s extends n{constructor({content:t,time:e,type:n,fontSize:s,color:o,timeStamp:i,pool:a,userHash:r,rowId:l}){super(t,e,n,s,o);this.timeStamp=i;this.pool=a;this.userHash=r;this.rowId=l;this.pDataArray=[e,n,s,o,i,a,r,l]}text(){const t=this.pDataArray.join(",");return`<d p="${t}">${this.content}</d>`}static parse(t){const e=t.getAttribute("p");const[n,o,i,a,r,l,c,h]=e.split(",");const u=t.innerHTML;return new s({content:u,time:n,type:o,fontSize:i,color:a,timeStamp:r,pool:l,userHash:c,rowId:h})}}class o{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 i extends n{constructor({content:t,time:e,type:n,fontSize:s,color:o,typeTag:i,colorTag:a,endTime:r}){super(t,e,n,s,o);this.typeTag=i;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:n,blockTypes:s,resolution:o}){this.danmakus=t;this.title=e;this.fontStyles=n;this.blockTypes=s;this.resolution=o}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,n){this.horizontal=[];this.vertical=[];this.resolution=e;this.duration=n*1e3;this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.fontSizes={25:`36pt ${t}`,18:`26pt ${t}`};this.danmakuType={1:"normal",2:"normal",3:"normal",4:"bottom",5:"top",6:"reversed",7:"special",8:"special"}}getHorizonalTags(t){this.context.font=this.fontSizes[t.fontSize];const e=this.context.measureText(t.content);const n=e.width/2;const s=(e.emHeightAscent+e.emHeightDescent)/2;return`\\move(${1920+n}, ${10+s}, ${-n}, ${10+s}, 0, ${this.duration})`}getVerticalTags(t){if(this.danmakuType[t.type]==="top"){return`\\pos(960, 20)`}else{return`\\pos(960, 1060)`}}push(t){let e=null;let n=null;switch(this.danmakuType[t.type]){case"normal":case"reversed":{e=this.getHorizonalTags(t);n=this.horizontal;break}case"top":case"bottom":{e=this.getVerticalTags(t);n=this.vertical;break}case"special":default:{throw new Error("Danmaku type not supported")}}const s={tags:e};n.push(s);return s}}class l{constructor({title:t,font:e,alpha:n,duration:s,blockTypes:o,resolution:i}){this.title=t;this.font=e;this.alpha=Math.round(n*100);this.duration=s;this.blockTypes=o;this.resolution=i;this.danmakuStack=new r(e,i)}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 n of t.danmakus){if(this.blockTypes.concat(7,8).indexOf(n.type)!==-1){continue}const[t,s]=this.convertTime(parseFloat(n.time),this.duration);e.push(new i({content:n.content,time:t,endTime:s,type:n.type,fontSize:n.fontSize,color:n.color,typeTag:this.convertType(n),colorTag:this.convertColor(parseInt(n.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 n=t.toString(16);const s=n.substring(4,6);const o=n.substring(2,4);const i=n.substring(0,2);return`\\c&H${i}${o}${s}&`}convertTime(t,e){function n(t){return Math.round(t*100)/100}function s(t){let e=0;let s=0;while(t>=60){t-=60;s++}while(s>=60){s-=60;e++}return`${e}:${s.toString().padStart(2,"0")}:${n(t).toString().padStart(4,"0")}`}return[s(t),s(t+e)]}}return{export:{AssDanmaku:i,AssDanmakuDocument:a,Danmaku:n,DanmakuConverter:l,DanmakuStack:r,XmlDanmaku:s,XmlDanmakuDocument:o}}}})();

View File

@ -1 +1 @@
(()=>{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:"Micorosoft Yahei UI",alpha:.6,duration:10,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 <button\n class="gui-settings-flat-button"\n id="download-danmaku">\n <i class="icon-danmaku"></i>\n <span>下载弹幕</span>\n <a id="danmaku-link" style="display:none"></a>\n </button>`,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)}})}}}}})();
(()=>{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:"Micorosoft 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 <button\n class="gui-settings-flat-button"\n id="download-danmaku">\n <i class="icon-danmaku"></i>\n <span>下载弹幕</span>\n <a id="danmaku-link" style="display:none"></a>\n </button>`,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)}})}}}}})();

View File

@ -100,10 +100,12 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
class DanmakuStack
{
constructor(font, resolution)
constructor(font, resolution, duration)
{
this.horizontal = [];
this.vertical = [];
this.resolution = resolution;
this.duration = duration * 1000; // 毫秒
this.canvas = document.createElement("canvas");
this.context = this.canvas.getContext("2d");
// XML字体大小到实际大小的表
@ -121,16 +123,34 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
7: "special",
8: "special",
};
this.margin = 10;
}
getTextSize(danmaku)
{
this.context.font = this.fontSizes[danmaku.fontSize];
const metrics = this.context.measureText(danmaku.content);
const x = metrics.width / 2;
const y = (metrics.emHeightAscent + metrics.emHeightDescent) / 2;
return [x, y];
}
getHorizonalTags(danmaku)
{
// TODO: place horizontal tags
return `\\pos(960, 540)`;
const [x, y] = this.getTextSize(danmaku);
return `\\move(${this.resolution.x + x}, ${this.margin + y}, ${-x}, ${this.margin + y}, 0, ${this.duration})`;
}
getVerticalTags(danmaku)
{
// TODO: place verizontal tags
return `\\pos(960, 540)`;
const [, y] = this.getTextSize(danmaku);
if (this.danmakuType[danmaku.type] === "top")
{
return `\\pos(${this.resolution.x / 2}, ${this.margin + y})`;
}
else
{
return `\\pos(${this.resolution.x / 2}, ${this.resolution.y - this.margin - y})`;
}
}
push(danmaku)
{

View File

@ -15,7 +15,7 @@
title,
font: "Micorosoft Yahei UI",
alpha: 0.6,
duration: 10,
duration: 5,
blockTypes: [],
resolution: {
x: 1920,