Refactor download ass danmaku

This commit is contained in:
the1812 2020-10-17 23:45:30 +08:00
parent 33e90d6223
commit 17371cdc2a
8 changed files with 77 additions and 66 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -86,7 +86,7 @@
"disable-profile-popup.min.js": "69901EC9A3D15D585F61B1370DC69003CE5869499CAC9C57A03B24511F338A2D",
"double-click-fullscreen.min.js": "C6D95B92ECDE67F2C0A3C6B6E4DC655C524F6A98CE0D48733ADCE4ABA780A47B",
"download-audio.min.js": "1F4536DE4FF302BFD026CA17E028AF8EB037FB6D0CB355692549DECAEAE0E8C9",
"download-danmaku.min.js": "B8B31AAAC93548DD324D751CD2E3342B5850F684594A59C768C7DBB72D6451F5",
"download-danmaku.min.js": "BCDC6878CE6A8BC6FCF6B3154FD42861C7B442F21107C67D94EEEAF2B72A3DB9",
"download-live-records.min.js": "7EF26D22D22EB75A6B27B78B3DB0E2ADE6004587C11B0C2893CF1CCB3B6FAB6F",
"download-subtitle.min.js": "EAD1F63E53C5A0A9877EBF655B68FB3438601D2869F31D0D4A2F7BD2A215E5F3",
"download-video.min.css": "E312176F7A6AA8492FCF0E6422327996D8B9FAB866A39CEA237E43FE353B6569",

Binary file not shown.

View File

@ -1 +1 @@
(()=>{return(t,e)=>{const{getFriendlyTitle:n}=e.import("title");const{DanmakuInfo:a}=e.import("video-info");const{DanmakuConverter:i}=e.import("danmaku-converter");async function o(t){const e=n();const a={font:"微软雅黑",alpha:.4,duration:t=>{switch(t.type){case 4:case 5:return 4;default:return 6}},blockTypes:[7,8],resolution:{x:1920,y:1080},bottomMarginPercent:.15,bold:false};let o={...a,title:e};try{await loadDanmakuSettingsPanel();const t=t=>{const e=parseFloat(dq(t).style.transform.replace(/translateX\(([\d\.]+)/,"$1"));return e*4/188};const e=t=>{const e=parseFloat(dq(t).style.transform.replace(/translateX\(([\d\.]+)/,"$1"));const n={0:0,47:1,94:2,141:3,188:4}[e];return n};o.font=dq(".bilibili-player-video-danmaku-setting-right-font .bui-select-result").innerText;o.alpha=(100-parseFloat(dq(".bilibili-player-setting-opacity .bui-thumb-tooltip").innerText))/100;o.duration=(()=>{const e=18-3*t(".bilibili-player-setting-speedplus .bui-thumb");return t=>{switch(t.type){case 4:case 5:return 4;default:return e}}})();o.blockTypes=(()=>{let t=[];const e={".bilibili-player-block-filter-type[ftype=scroll]":[1,2,3],".bilibili-player-block-filter-type[ftype=top]":[5],".bilibili-player-block-filter-type[ftype=bottom]":[4],".bilibili-player-block-filter-type[ftype=color]":["color"]};for(const[n,a]of Object.entries(e)){if(dq(n).classList.contains("disabled")){t=t.concat(a)}}return t.concat(7,8)})();const n=1.4-.2*t(".bilibili-player-setting-fontsize .bui-thumb");o.resolution={x:Math.round(1920*n),y:Math.round(1080*n)};o.bottomMarginPercent=[.75,.5,.25,0,0][e(".bilibili-player-setting-area .bui-thumb")];if(o.bottomMarginPercent===0&&dq(".bilibili-player-video-danmaku-setting-left-preventshade input").checked){o.bottomMarginPercent=.15}o.bold=dq(".bilibili-player-video-danmaku-setting-right-font-bold input").checked;const i=localStorage.getItem("bilibili_player_settings");if(i){const t=JSON.parse(i);const e=_.get(t,"block.list",[]);o.blockFilter=(t=>{for(const n of e){if(!n.s){continue}switch(n.t){case"keyword":{if(t.content.includes(n.v)){return false}break}case"regexp":{if(new RegExp(n.v).test(t.content)){return false}break}case"user":{if(t.userHash===n.v){return false}break}}}return true})}}catch(t){o={...o,...a}}for(const[t,e]of Object.entries(o)){if(e===undefined||e===null){console.warn("danmaku config invalid for key",t,", value =",e);o[t]=a[e]}}console.log(o);const s=new i(o);const r=s.convertToAssDocument(t);return r.generateAss()}async function s(t){const e=n();const i=new a((unsafeWindow||window).cid);await i.fetchInfo();const s=await(async()=>{if(t===true){return new Blob([await o(i.rawXML)],{type:"text/plain"})}else{return new Blob([i.rawXML],{type:"text/plain"})}})();const r=URL.createObjectURL(s);const l=dq("#danmaku-link");const c=l.getAttribute("href");if(c){URL.revokeObjectURL(c)}l.setAttribute("download",`${e}.${t?"ass":"xml"}`);l.setAttribute("href",r);l.click()}return{export:{downloadDanmaku:s,convertToAss:o},widget:{content:`\n<a id="danmaku-link" style="display:none"></a>\n<button\n class="gui-settings-flat-button"\n id="download-danmaku-xml">\n<i class="icon-danmaku"></i>\n<span>下载弹幕<span>(XML)</span></span>\n</button>\n<button\n class="gui-settings-flat-button"\n id="download-danmaku-ass">\n<i class="icon-danmaku"></i>\n<span>下载弹幕<span>(ASS)</span></span>\n</button>\n`,condition:async()=>{let t=await SpinQuery.select(()=>(unsafeWindow||window).cid);return Boolean(t)},success:()=>{const t=dq("#download-danmaku-xml");const e=dq("#download-danmaku-ass");const n=[t,e];const a=(t,e)=>{t.addEventListener("click",async()=>{try{n.forEach(t=>t.disabled=true);await s(e)}catch(t){logError(t)}finally{n.forEach(t=>t.disabled=false)}})};a(t,false);a(e,true)}}}}})();
(()=>{return(t,n)=>{const{getFriendlyTitle:e}=n.import("title");const{DanmakuInfo:o}=n.import("video-info");const{DanmakuConverter:a}=n.import("danmaku-converter");async function s(t){const n=e();const o={font:"微软雅黑",alpha:.4,duration:t=>{switch(t.type){case 4:case 5:return 4;default:return 6}},blockTypes:[7,8],resolution:{x:1920,y:1080},bottomMarginPercent:.15,bold:false};let s={...o,title:n};try{await loadDanmakuSettingsPanel();const t=localStorage.getItem("bilibili_player_settings");if(t){const n=JSON.parse(t);const e=(t,e)=>_.get(n,`setting_config.${t}`,e);s.blockTypes=(()=>{const t=[];const e={scroll:[1,2,3],top:[5],bottom:[4],color:["color"]};for(const[o,a]of Object.entries(e)){if(_.get(n,`block.type_${o}`,true)===false){t.push(...a)}}return t.concat(7,8)})();s.bold=e("bold",false);s.alpha=parseFloat(e("opacity","0.4"));const o=1.4-.4*e("fontsize",1);s.resolution={x:Math.round(1920*o),y:Math.round(1080*o)};s.duration=(()=>{const t=18-3*e("speedplus",0);return n=>{switch(n.type){case 4:case 5:return 4;default:return t}}})();const a=e("danmakuArea",0);s.bottomMarginPercent=a>=100?0:a/100;if(s.bottomMarginPercent===0&&e("preventshade",false)){s.bottomMarginPercent=.15}const r=_.get(n,"block.list",[]);s.blockFilter=(t=>{for(const n of r){if(!n.s){continue}switch(n.t){case"keyword":{if(t.content.includes(n.v)){return false}break}case"regexp":{if(new RegExp(n.v).test(t.content)){return false}break}case"user":{if(t.userHash===n.v){return false}break}}}return true})}else{console.warn("[弹幕转换] 未找到播放器设置");s={...s,...o}}s.font=dq(".bilibili-player-video-danmaku-setting-right-font .bui-select-result").innerText}catch(t){logError(t);s={...s,...o}}for(const[t,n]of Object.entries(s)){if(n===undefined||n===null){console.warn("danmaku config invalid for key",t,", value =",n);s[t]=o[n]}}console.log(s);const r=new a(s);const c=r.convertToAssDocument(t);return c.generateAss()}async function r(t){const n=e();const a=new o((unsafeWindow||window).cid);await a.fetchInfo();const r=await(async()=>{if(t===true){return new Blob([await s(a.rawXML)],{type:"text/plain"})}else{return new Blob([a.rawXML],{type:"text/plain"})}})();const c=URL.createObjectURL(r);const i=dq("#danmaku-link");const l=i.getAttribute("href");if(l){URL.revokeObjectURL(l)}i.setAttribute("download",`${n}.${t?"ass":"xml"}`);i.setAttribute("href",c);i.click()}return{export:{downloadDanmaku:r,convertToAss:s},widget:{content:`\n<a id="danmaku-link" style="display:none"></a>\n<button\n class="gui-settings-flat-button"\n id="download-danmaku-xml">\n<i class="icon-danmaku"></i>\n<span>下载弹幕<span>(XML)</span></span>\n</button>\n<button\n class="gui-settings-flat-button"\n id="download-danmaku-ass">\n<i class="icon-danmaku"></i>\n<span>下载弹幕<span>(ASS)</span></span>\n</button>\n`,condition:async()=>{let t=await SpinQuery.select(()=>(unsafeWindow||window).cid);return Boolean(t)},success:()=>{const t=dq("#download-danmaku-xml");const n=dq("#download-danmaku-ass");const e=[t,n];const o=(t,n)=>{t.addEventListener("click",async()=>{try{e.forEach(t=>t.disabled=true);await r(n)}catch(t){logError(t)}finally{e.forEach(t=>t.disabled=false)}})};o(t,false);o(n,true)}}}}})();

View File

@ -27,25 +27,47 @@ export async function convertToAss(xml: string) {
let config = { ...defaultConfig, title } as DanmakuConverterConfig
try {
await loadDanmakuSettingsPanel()
const getSliderFactor = (selector: string) => {
const transform = parseFloat((dq(selector) as HTMLElement).style.transform!.replace(/translateX\(([\d\.]+)/, '$1'))
return transform * 4 / 188
const playerSettingsJson = localStorage.getItem('bilibili_player_settings')
if (playerSettingsJson) {
const playerSettings = JSON.parse(playerSettingsJson)
const getConfig = <T>(prop: string, defaultValue?: T): T =>
_.get(playerSettings, `setting_config.${prop}`, defaultValue)
// 屏蔽类型
config.blockTypes = (() => {
const result: (DanmakuType | 'color')[] = []
const blockValues = {
scroll: [1, 2, 3],
top: [5],
bottom: [4],
color: ['color']
}
const getSliderIndex = (selector: string) => {
const transform = parseFloat((dq(selector) as HTMLElement).style.transform!.replace(/translateX\(([\d\.]+)/, '$1')) as 0 | 47 | 94 | 141 | 188
const index = {
0: 0,
47: 1,
94: 2,
141: 3,
188: 4
}[transform]
return index
for (const [type, value] of Object.entries(blockValues)) {
if (_.get(playerSettings, `block.type_${type}`, true) === false) {
result.push(...value as (DanmakuType | 'color')[])
}
config.font = (dq('.bilibili-player-video-danmaku-setting-right-font .bui-select-result') as HTMLElement).innerText
config.alpha = (100 - parseFloat((dq('.bilibili-player-setting-opacity .bui-thumb-tooltip') as HTMLElement).innerText)) / 100
}
return result.concat(7, 8) // 高级弹幕不做转换
})()
// 加粗
config.bold = getConfig('bold', false)
// 不透明度
config.alpha = parseFloat(getConfig('opacity', '0.4'))
// 分辨率
const resolutionFactor = 1.4 - 0.4 * getConfig('fontsize', 1)
config.resolution = {
x: Math.round(1920 * resolutionFactor),
y: Math.round(1080 * resolutionFactor),
}
// 弹幕持续时长
config.duration = (() => {
const scrollDuration = 18 - 3 * getSliderFactor('.bilibili-player-setting-speedplus .bui-thumb')
const scrollDuration = 18 - 3 * getConfig('speedplus', 0)
return (danmaku: { type: number }) => {
switch (danmaku.type) {
case 4:
@ -56,38 +78,16 @@ export async function convertToAss(xml: string) {
}
}
})()
config.blockTypes = (() => {
let result: (DanmakuType | 'color')[] = []
const blockValues = {
'.bilibili-player-block-filter-type[ftype=scroll]': [1, 2, 3],
'.bilibili-player-block-filter-type[ftype=top]': [5],
'.bilibili-player-block-filter-type[ftype=bottom]': [4],
'.bilibili-player-block-filter-type[ftype=color]': ['color']
// ".bilibili-player-block-filter-type[ftype=special]": [7, 8],
}
for (const [type, value] of Object.entries(blockValues)) {
if ((dq(type) as HTMLElement).classList.contains('disabled')) {
result = result.concat(value as (DanmakuType | 'color')[])
}
}
return result.concat(7, 8)
})()
const resolutionFactor = 1.4 - 0.2 * getSliderFactor('.bilibili-player-setting-fontsize .bui-thumb') // 改变分辨率来调整字体大小
config.resolution = {
x: Math.round(1920 * resolutionFactor),
y: Math.round(1080 * resolutionFactor),
}
config.bottomMarginPercent = [0.75, 0.5, 0.25, 0, 0][getSliderIndex('.bilibili-player-setting-area .bui-thumb')]
if (config.bottomMarginPercent === 0 && (dq('.bilibili-player-video-danmaku-setting-left-preventshade input') as HTMLInputElement).checked) // 无显示区域限制时要检查是否开启防挡字幕
{
// 底部间距
const bottomMargin = getConfig('danmakuArea', 0)
config.bottomMarginPercent = bottomMargin >= 100 ? 0 : bottomMargin / 100
// 无显示区域限制时要检查是否开启防挡字幕
if (config.bottomMarginPercent === 0 && getConfig('preventshade', false)) {
config.bottomMarginPercent = 0.15
}
config.bold = (dq('.bilibili-player-video-danmaku-setting-right-font-bold input') as HTMLInputElement).checked
// 用户屏蔽词
const playerSettingsJson = localStorage.getItem('bilibili_player_settings')
if (playerSettingsJson) {
const playerSettings = JSON.parse(playerSettingsJson)
const blockSettings = _.get(playerSettings, 'block.list', []) as {
/** 类型 */
t: 'keyword' | 'regexp' | 'user',
@ -125,9 +125,20 @@ export async function convertToAss(xml: string) {
}
return true
}
} else {
console.warn('[弹幕转换] 未找到播放器设置')
config = {
...config,
...defaultConfig
}
}
// 字体直接从 HTML 里取了, localStorage 里是 font-family 解析更麻烦些
config.font = (dq('.bilibili-player-video-danmaku-setting-right-font .bui-select-result') as HTMLElement).innerText
} catch (error) {
// The default config
logError(error)
config = {
...config,
...defaultConfig,