mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Refactor download ass danmaku
This commit is contained in:
parent
33e90d6223
commit
17371cdc2a
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
@ -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",
|
||||
|
||||
BIN
min/bundle.zip
BIN
min/bundle.zip
Binary file not shown.
2
min/download-danmaku.min.js
vendored
2
min/download-danmaku.min.js
vendored
@ -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)}}}}})();
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user