mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-20 04:01:20 -08:00
refactor(danmuku): [PKG-DANMUKU-06] migrate runtime and preserve public types
This commit is contained in:
1 parent
abc8008da7
commit
24b883d862
64 files changed
+14020
-633
No files matched your search
+209
-244
@@ -1,114 +1,96 @@
|
||||
export type Mode = 0 | 1 | 2
|
||||
export type Danmuku
|
||||
= | Danmu[]
|
||||
| string // URL
|
||||
| (() => Promise<Danmu[]>)
|
||||
| Promise<Danmu[]>
|
||||
|
||||
export interface Slider {
|
||||
min?: number
|
||||
max?: number
|
||||
steps?: {
|
||||
name?: string
|
||||
value?: number | string
|
||||
show?: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface Danmu {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string
|
||||
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number
|
||||
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku
|
||||
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number
|
||||
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [number | `${number}%`, number | `${number}%`]
|
||||
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number
|
||||
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[]
|
||||
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`
|
||||
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean
|
||||
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string
|
||||
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?:
|
||||
| boolean
|
||||
| {
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginDanmukuDefinitions {
|
||||
export type Mode = 0 | 1 | 2
|
||||
export type Danmuku = Danmu[] | string // URL
|
||||
| (() => Promise<Danmu[]>) | Promise<Danmu[]>
|
||||
export interface Slider {
|
||||
min?: number
|
||||
max?: number
|
||||
steps?: {
|
||||
name?: string
|
||||
value?: number | string
|
||||
show?: boolean
|
||||
}[]
|
||||
}
|
||||
export interface Danmu {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
export interface Option {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [
|
||||
number | `${number}%`,
|
||||
number | `${number}%`,
|
||||
]
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[]
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?: boolean | {
|
||||
xMin?: number
|
||||
xMax?: number
|
||||
yMin?: number
|
||||
@@ -120,140 +102,123 @@ export interface Option {
|
||||
smoothing?: number
|
||||
flattening?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: { time: number, value: number }[]
|
||||
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean
|
||||
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean
|
||||
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number
|
||||
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number
|
||||
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark'
|
||||
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider
|
||||
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider
|
||||
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[]
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: {
|
||||
time: number
|
||||
value: number
|
||||
}[]
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark'
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[]
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmuku'
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean
|
||||
}
|
||||
export const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmuku'
|
||||
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result
|
||||
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>
|
||||
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result
|
||||
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result
|
||||
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result
|
||||
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void
|
||||
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result
|
||||
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option
|
||||
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean
|
||||
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean
|
||||
declare const artplayerPluginDanmuku: typeof artplayerPluginDanmukuDefinitions.artplayerPluginDanmuku
|
||||
declare namespace artplayerPluginDanmuku {
|
||||
export type Mode = artplayerPluginDanmukuDefinitions.Mode
|
||||
export type Danmuku = artplayerPluginDanmukuDefinitions.Danmuku
|
||||
export type Slider = artplayerPluginDanmukuDefinitions.Slider
|
||||
export type Danmu = artplayerPluginDanmukuDefinitions.Danmu
|
||||
export type Option = artplayerPluginDanmukuDefinitions.Option
|
||||
export type Result = artplayerPluginDanmukuDefinitions.Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDanmuku
|
||||
|
||||
export = artplayerPluginDanmuku
|
||||
export as namespace artplayerPluginDanmuku;
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function e(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function i(t){if("string"!==typeof t)return[];const i=t.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(t=>{const i=t.groups.p.split(",");if(i.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(i[0]),mode:e(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function n({data:t}){const{xml:e,id:n}=t,a=i(e);globalThis.postMessage({danmus:a,id:n})}let a=0;function s(t,{signal:s,onCancel:r}={}){return new Promise((o,l)=>{let d,c,p,h=!1;const u=++a,m=()=>g(void 0,function(t){if(void 0!==t?.reason)return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(s));function f(){let t,e=!1;try{if(d){const t=d;d=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==c){const n=c;c=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function g(t,e){if(h)return;h=!0;let i=arguments.length>1;s?.removeEventListener("abort",m),p?.();try{f()}catch(n){i||(e=n),i=!0}i?l(e):o(t)}function y(t,e){if(!h){console.error("Error parsing Bilibili Danmu:",e);try{g(i(t))}catch(n){g(void 0,n)}}}s?.aborted?m():(s?.addEventListener("abort",m),p=r?.(m),h?p?.():async function(){const a=s?await fetch(t,{signal:s}):await fetch(t);if(h)return;const r=await a.text();if(!h)try{const t=`\n ${e.toString()}\n ${i.toString()}\n onmessage = ${n.toString()}\n `;if(c=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),h)return void f();if(d=new Worker(c),h)return void f();d.onmessage=t=>{if(h||t.data?.id!==u)return;const{danmus:e}=t.data;Array.isArray(e)?g(e):g(void 0,new Error("Invalid Bilibili Danmu worker response"))},d.onerror=t=>{t.preventDefault?.(),y(r,t.error||t)},d.onmessageerror=t=>y(r,t.error||t),d.postMessage({xml:r,id:u})}catch(o){y(r,o)}}().catch(t=>g(void 0,t)))})}const r=new WeakMap,o=Symbol("cancelled danmuku input");function l(t){return r.has(t)||r.set(t,{closed:!1,tasks:new Set,emitting:[]}),r.get(t)}function d(t){const e=l(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function c(t){const e=l(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function p(t,e,i){const n=t.states[e]||[];for(let a=0;a<n.length;a++)i(n[a]);return n}class h{constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const a=n.$ref.offsetTop,s=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=s+o,d=e-l,c=l/n.$restTime,p={};p.top=a,p.left=s,p.height=r,p.width=o,p.right=d,p.speed=c,p.distance=l,p.time=n.$restTime,p.mode=n.mode,t.push(p)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emit",e=>{switch(e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.left=`${t}px`,e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}})}continue(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("stop",e=>{switch(this.owner.setState(e,"emit"),e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}}),this}suspend(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("emit",e=>{switch(this.owner.setState(e,"stop"),e.mode){case 0:{const i=t-(this.owner.getLeft(e.$ref)-this.owner.getLeft(this.owner.$player));e.$ref.style.transform=`translLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function e(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function i(t){if("string"!==typeof t)return[];const i=t.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(t=>{const i=t.groups.p.split(",");if(i.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(i[0]),mode:e(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function n({data:t}){const{xml:e,id:n}=t,a=i(e);globalThis.postMessage({danmus:a,id:n})}let a=0;function s(t,{signal:s,onCancel:r}={}){return new Promise((o,l)=>{let d,c,p,h=!1;const u=++a,m=()=>g(void 0,function(t){if(void 0!==t?.reason)return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(s));function f(){let t,e=!1;try{if(d){const t=d;d=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==c){const n=c;c=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function g(t,e){if(h)return;h=!0;let i=arguments.length>1;s?.removeEventListener("abort",m),p?.();try{f()}catch(n){i||(e=n),i=!0}i?l(e):o(t)}function y(t,e){if(!h){console.error("Error parsing Bilibili Danmu:",e);try{g(i(t))}catch(n){g(void 0,n)}}}s?.aborted?m():(s?.addEventListener("abort",m),p=r?.(m),h?p?.():async function(){const a=s?await fetch(t,{signal:s}):await fetch(t);if(h)return;const r=await a.text();if(!h)try{const t=`\n ${e.toString()}\n ${i.toString()}\n onmessage = ${n.toString()}\n `;if(c=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),h)return void f();if(d=new Worker(c),h)return void f();d.onmessage=t=>{if(h||t.data?.id!==u)return;const{danmus:e}=t.data;Array.isArray(e)?g(e):g(void 0,new Error("Invalid Bilibili Danmu worker response"))},d.onerror=t=>{t.preventDefault?.(),y(r,t.error||t)},d.onmessageerror=t=>y(r,t.error||t),d.postMessage({xml:r,id:u})}catch(o){y(r,o)}}().catch(t=>g(void 0,t)))})}const r=new WeakMap,o=Symbol("cancelled danmuku input");function l(t){return r.has(t)||r.set(t,{closed:!1,tasks:new Set,emitting:[]}),r.get(t)}function d(t){const e=l(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function c(t){const e=l(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function p(t,e,i){const n=t.states[e]||[];for(let a=0;a<n.length;a++)i(n[a]);return n}class h{constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const a=n.$ref.offsetTop,s=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=s+o,d=e-l,c=l/n.$restTime,p={};p.top=a,p.left=s,p.height=r,p.width=o,p.right=d,p.speed=c,p.distance=l,p.time=n.$restTime,p.mode=n.mode,t.push(p)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emit",e=>{switch(e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.left=`${t}px`,e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}})}continue(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("stop",e=>{switch(this.owner.setState(e,"emit"),e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}}),this}suspend(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("emit",e=>{switch(this.owner.setState(e,"stop"),e.mode){case 0:{const i=t-(this.owner.getLeft(e.$ref)-this.owner.getLeft(this.owner.$player));e.$ref.style.transform=`translLine truncated
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,r=Math.pow,o=(e,i,n)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[i]=n,l=(t,e)=>{for(var i in e||(e={}))a.call(e,i)&&o(t,i,e[i]);if(n)for(var i of n(e))s.call(e,i)&&o(t,i,e[i]);return t},d=(t,n)=>e(t,i(n)),c=(t,e,i)=>new Promise((n,a)=>{var s=t=>{try{o(i.next(t))}catch(e){a(e)}},r=t=>{try{o(i.throw(t))}catch(e){a(e)}},o=t=>t.done?n(t.value):Promise.resolve(t.value).then(s,r);o((i=i.apply(t,e)).next())});function p(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function h(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(e[0]),mode:h(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function m({data:t}){const{xml:e,id:i}=t,n=u(e);globalThis.postMessage({danmus:n,id:i})}let f=0;function g(t,{signal:e,onCancel:i}={}){return new Promise((n,a)=>{let s,r,o,l=!1;const d=++f,p=()=>y(void 0,function(t){if(void 0!==(null==t?void 0:t.reason))return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(e));function g(){let t,e=!1;try{if(s){const t=s;s=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==r){const n=r;r=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function y(t,i){if(l)return;l=!0;let s=arguments.length>1;null==e||e.removeEventListener("abort",p),null==o||o();try{g()}catch(r){s||(i=r),s=!0}s?a(i):n(t)}function v(t,e){if(!l){console.error("Error parsing Bilibili Danmu:",e);try{y(u(t))}catch(i){y(void 0,i)}}}(null==e?void 0:e.aborted)?p():(null==e||e.addEventListener("abort",p),o=null==i?void 0:i(p),l?null==o||o():function(){return c(this,null,function*(){const i=e?yield fetch(t,{signal:e}):yield fetch(t);if(l)return;const n=yield i.text();if(!l)try{const t=`\n ${h.toString()}\n ${u.toString()}\n onmessage = ${m.toString()}\n `;if(r=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),l)return void g();if(s=new Worker(r),l)return void g();s.onmessage=t=>{var e;if(l||(null==(e=t.data)?void 0:e.id)!==d)return;const{danmus:i}=t.data;Array.isArray(i)?y(i):y(void 0,new Error("Invalid Bilibili Danmu worker response"))},s.onerror=t=>{var e;null==(e=t.preventDefault)||e.call(t),v(n,t.error||t)},s.onmessageerror=t=>v(n,t.error||t),s.postMessage({xml:n,id:d})}catch(a){v(n,a)}})}().catch(t=>y(void 0,t)))})}const y=new WeakMap,v=Symbol("cancelled danmuku input");function w(t){return y.has(t)||y.set(t,{closed:!1,tasks:new Set,emitting:[]}),y.get(t)}function k(t){const e=w(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function x(t){const e=w(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function b(t,e,i){const n=t.states[e]||[];for(let a=0;a<n.length;a++)i(n[a]);return n}class ${constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const a=n.$ref.offsetTop,s=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=s+o,d=e-l,c=l/n.$restTime,p={};p.top=a,p.left=s,p.height=r,p.width=o,p.right=d,p.speed=c,p.distance=l,p.time=n.$restTime,p.mode=n.mode,t.push(p)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emitLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,r=Math.pow,o=(e,i,n)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[i]=n,l=(t,e)=>{for(var i in e||(e={}))a.call(e,i)&&o(t,i,e[i]);if(n)for(var i of n(e))s.call(e,i)&&o(t,i,e[i]);return t},d=(t,n)=>e(t,i(n)),c=(t,e,i)=>new Promise((n,a)=>{var s=t=>{try{o(i.next(t))}catch(e){a(e)}},r=t=>{try{o(i.throw(t))}catch(e){a(e)}},o=t=>t.done?n(t.value):Promise.resolve(t.value).then(s,r);o((i=i.apply(t,e)).next())});function p(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function h(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(e[0]),mode:h(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function m({data:t}){const{xml:e,id:i}=t,n=u(e);globalThis.postMessage({danmus:n,id:i})}let f=0;function g(t,{signal:e,onCancel:i}={}){return new Promise((n,a)=>{let s,r,o,l=!1;const d=++f,p=()=>y(void 0,function(t){if(void 0!==(null==t?void 0:t.reason))return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(e));function g(){let t,e=!1;try{if(s){const t=s;s=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==r){const n=r;r=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function y(t,i){if(l)return;l=!0;let s=arguments.length>1;null==e||e.removeEventListener("abort",p),null==o||o();try{g()}catch(r){s||(i=r),s=!0}s?a(i):n(t)}function v(t,e){if(!l){console.error("Error parsing Bilibili Danmu:",e);try{y(u(t))}catch(i){y(void 0,i)}}}(null==e?void 0:e.aborted)?p():(null==e||e.addEventListener("abort",p),o=null==i?void 0:i(p),l?null==o||o():function(){return c(this,null,function*(){const i=e?yield fetch(t,{signal:e}):yield fetch(t);if(l)return;const n=yield i.text();if(!l)try{const t=`\n ${h.toString()}\n ${u.toString()}\n onmessage = ${m.toString()}\n `;if(r=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),l)return void g();if(s=new Worker(r),l)return void g();s.onmessage=t=>{var e;if(l||(null==(e=t.data)?void 0:e.id)!==d)return;const{danmus:i}=t.data;Array.isArray(i)?y(i):y(void 0,new Error("Invalid Bilibili Danmu worker response"))},s.onerror=t=>{var e;null==(e=t.preventDefault)||e.call(t),v(n,t.error||t)},s.onmessageerror=t=>v(n,t.error||t),s.postMessage({xml:n,id:d})}catch(a){v(n,a)}})}().catch(t=>y(void 0,t)))})}const y=new WeakMap,v=Symbol("cancelled danmuku input");function w(t){return y.has(t)||y.set(t,{closed:!1,tasks:new Set,emitting:[]}),y.get(t)}function k(t){const e=w(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function x(t){const e=w(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function b(t,e,i){const n=t.states[e]||[];for(let a=0;a<n.length;a++)i(n[a]);return n}class ${constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const a=n.$ref.offsetTop,s=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=s+o,d=e-l,c=l/n.$restTime,p={};p.top=a,p.left=s,p.height=r,p.width=o,p.right=d,p.speed=c,p.distance=l,p.time=n.$restTime,p.mode=n.mode,t.push(p)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emitLine truncated
|
||||
@@ -665,16 +665,18 @@ class Scheduler {
|
||||
danmu.$lastStartTime = Date.now();
|
||||
danmu.$restTime = owner.speed;
|
||||
const distance = clientWidth + ref.clientWidth;
|
||||
const { result: top } = await operation.wait(owner.postMessage({
|
||||
const reply = await operation.wait(owner.postMessage({
|
||||
type: "getDanmuTop",
|
||||
target: { mode: danmu.mode, height: ref.clientHeight, speed: distance / danmu.$restTime },
|
||||
visibles: owner.visibles,
|
||||
antiOverlap: owner.option.antiOverlap,
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
// Valid margins are numeric. Preserve the old raw fallback for unsupported strings.
|
||||
marginBottom: owner.marginBottom,
|
||||
marginTop: owner.marginTop
|
||||
}));
|
||||
const top = typeof reply === "symbol" ? void 0 : reply.result;
|
||||
if (!this.active(operation) || danmu.$ref !== ref)
|
||||
return;
|
||||
if (top !== void 0) {
|
||||
@@ -948,6 +950,7 @@ class Danmuku {
|
||||
if (!task.active())
|
||||
return this;
|
||||
errorHandle(Array.isArray(danmus), "Danmuku need return an array as result");
|
||||
const rows = danmus;
|
||||
if (danmuku === void 0) {
|
||||
this.reset();
|
||||
if (!task.active())
|
||||
@@ -956,10 +959,10 @@ class Danmuku {
|
||||
this.states = { wait: [], ready: [], emit: [], stop: [] };
|
||||
this.renderer.clear();
|
||||
}
|
||||
for (let index = 0; index < danmus.length; index++) {
|
||||
for (let index = 0; index < rows.length; index++) {
|
||||
if (!task.active())
|
||||
return this;
|
||||
const danmu = danmus[index];
|
||||
const danmu = rows[index];
|
||||
await task.emit(danmu);
|
||||
}
|
||||
if (task.active())
|
||||
@@ -1074,6 +1077,7 @@ class Danmuku {
|
||||
return this.renderer.left($ref);
|
||||
}
|
||||
// 复杂运算交给 Web Worker 处理
|
||||
// Keep the historical empty default; unknown message types receive no reply.
|
||||
postMessage(message = {}) {
|
||||
return this.workerClient.request(message);
|
||||
}
|
||||
@@ -1312,8 +1316,9 @@ function heatmap(art, danmuku, option) {
|
||||
let closed = false;
|
||||
const active = () => !closed && !art.isDestroy;
|
||||
function listen(name, callback) {
|
||||
subscriptions.push([name, callback]);
|
||||
art.on(name, callback);
|
||||
const listener = callback;
|
||||
subscriptions.push([name, listener]);
|
||||
art.on(name, listener);
|
||||
}
|
||||
function dispose(removeControl) {
|
||||
if (closed)
|
||||
@@ -1351,18 +1356,19 @@ function heatmap(art, danmuku, option) {
|
||||
return;
|
||||
start = null;
|
||||
stop = null;
|
||||
element.innerHTML = "";
|
||||
const target = element;
|
||||
target.innerHTML = "";
|
||||
if (art.option.isLive)
|
||||
return;
|
||||
const shape = heatmapGeometry({ width: element.offsetWidth, height: element.offsetHeight, duration: art.duration, queue: danmuku.queue, option, points });
|
||||
const shape = heatmapGeometry({ width: target.offsetWidth, height: target.offsetHeight, duration: art.duration, queue: danmuku.queue, option, points });
|
||||
if (!shape || !active())
|
||||
return;
|
||||
const document2 = element.ownerDocument;
|
||||
const document2 = target.ownerDocument;
|
||||
if (!gradient)
|
||||
gradient = document2 ? "heatmap-solids" : `heatmap-solids-${++nextGradient}`;
|
||||
while (document2?.getElementById(gradient))
|
||||
gradient = `heatmap-solids-${++nextGradient}`;
|
||||
element.innerHTML = `
|
||||
target.innerHTML = `
|
||||
<svg viewBox="0 0 ${shape.width} ${shape.height}">
|
||||
<defs>
|
||||
<linearGradient id="${gradient}" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
@@ -1375,8 +1381,8 @@ function heatmap(art, danmuku, option) {
|
||||
<path fill="url(#${gradient})" d="${shape.path}"></path>
|
||||
</svg>
|
||||
`;
|
||||
start = query("#heatmap-start", element);
|
||||
stop = query("#heatmap-stop", element);
|
||||
start = query("#heatmap-start", target);
|
||||
stop = query("#heatmap-stop", target);
|
||||
progress(art.played);
|
||||
}
|
||||
function update(points) {
|
||||
@@ -1456,7 +1462,8 @@ class SettingLifecycle {
|
||||
dispose();
|
||||
else this.disposers.add(dispose);
|
||||
}
|
||||
write(target, key, value, apply = (value2) => target[key] = value2) {
|
||||
write(host, key, value, apply = (value2) => host[key] = value2) {
|
||||
const target = host;
|
||||
if (!this.active)
|
||||
return;
|
||||
const priority = () => typeof target.getPropertyPriority === "function" ? target.getPropertyPriority(key) : void 0;
|
||||
@@ -1847,16 +1854,17 @@ const style = ".artplayer-plugin-danmuku {\n display: flex;\n position: relati
|
||||
if (typeof document !== "undefined") {
|
||||
const id = "artplayer-plugin-danmuku";
|
||||
const pending = /* @__PURE__ */ Symbol.for("artplayer-plugin-danmuku.pending-style");
|
||||
let $style2 = document.getElementById(id) || document[pending];
|
||||
const styleDocument = document;
|
||||
let $style2 = document.getElementById(id) || styleDocument[pending];
|
||||
if (!$style2) {
|
||||
$style2 = document.createElement("style");
|
||||
$style2.id = id;
|
||||
if (document.readyState === "loading") {
|
||||
document[pending] = $style2;
|
||||
styleDocument[pending] = $style2;
|
||||
const ready = () => {
|
||||
document.removeEventListener("DOMContentLoaded", ready);
|
||||
if (document[pending] === $style2)
|
||||
delete document[pending];
|
||||
if (styleDocument[pending] === $style2)
|
||||
delete styleDocument[pending];
|
||||
const existing = document.getElementById(id);
|
||||
if (existing)
|
||||
existing.textContent = $style2.textContent;
|
||||
|
||||
@@ -661,16 +661,18 @@ var artplayerPluginDanmuku = (function() {
|
||||
danmu.$lastStartTime = Date.now();
|
||||
danmu.$restTime = owner.speed;
|
||||
const distance = clientWidth + ref.clientWidth;
|
||||
const { result: top } = await operation.wait(owner.postMessage({
|
||||
const reply = await operation.wait(owner.postMessage({
|
||||
type: "getDanmuTop",
|
||||
target: { mode: danmu.mode, height: ref.clientHeight, speed: distance / danmu.$restTime },
|
||||
visibles: owner.visibles,
|
||||
antiOverlap: owner.option.antiOverlap,
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
// Valid margins are numeric. Preserve the old raw fallback for unsupported strings.
|
||||
marginBottom: owner.marginBottom,
|
||||
marginTop: owner.marginTop
|
||||
}));
|
||||
const top = typeof reply === "symbol" ? void 0 : reply.result;
|
||||
if (!this.active(operation) || danmu.$ref !== ref)
|
||||
return;
|
||||
if (top !== void 0) {
|
||||
@@ -944,6 +946,7 @@ var artplayerPluginDanmuku = (function() {
|
||||
if (!task.active())
|
||||
return this;
|
||||
errorHandle(Array.isArray(danmus), "Danmuku need return an array as result");
|
||||
const rows = danmus;
|
||||
if (danmuku === void 0) {
|
||||
this.reset();
|
||||
if (!task.active())
|
||||
@@ -952,10 +955,10 @@ var artplayerPluginDanmuku = (function() {
|
||||
this.states = { wait: [], ready: [], emit: [], stop: [] };
|
||||
this.renderer.clear();
|
||||
}
|
||||
for (let index = 0; index < danmus.length; index++) {
|
||||
for (let index = 0; index < rows.length; index++) {
|
||||
if (!task.active())
|
||||
return this;
|
||||
const danmu = danmus[index];
|
||||
const danmu = rows[index];
|
||||
await task.emit(danmu);
|
||||
}
|
||||
if (task.active())
|
||||
@@ -1070,6 +1073,7 @@ var artplayerPluginDanmuku = (function() {
|
||||
return this.renderer.left($ref);
|
||||
}
|
||||
// 复杂运算交给 Web Worker 处理
|
||||
// Keep the historical empty default; unknown message types receive no reply.
|
||||
postMessage(message = {}) {
|
||||
return this.workerClient.request(message);
|
||||
}
|
||||
@@ -1235,7 +1239,8 @@ var artplayerPluginDanmuku = (function() {
|
||||
smoothing: 0.2,
|
||||
flattening: 0.2
|
||||
};
|
||||
const options = Object.assign({}, defaults, typeof option === "object" ? option : {});
|
||||
const configured = Object.assign({}, typeof option === "object" ? option : {});
|
||||
const options = Object.assign({}, defaults, configured);
|
||||
for (const key of Object.keys(defaults)) {
|
||||
if (!Number.isFinite(options[key]))
|
||||
options[key] = defaults[key];
|
||||
@@ -1244,7 +1249,8 @@ var artplayerPluginDanmuku = (function() {
|
||||
options.sampling = defaults.sampling;
|
||||
if (options.xMin === options.xMax || options.yMin === options.yMax)
|
||||
return null;
|
||||
const points = Array.isArray(input) && input.length ? [...input] : sampleHeatmap(queue, width, duration, options.sampling);
|
||||
const hasCustomPoints = Array.isArray(input) && input.length > 0;
|
||||
const points = hasCustomPoints ? [...input] : sampleHeatmap(queue, width, duration, options.sampling);
|
||||
if (!points.length || !points.every((point) => Array.isArray(point) && Number.isFinite(point[0]) && Number.isFinite(point[1]))) {
|
||||
return null;
|
||||
}
|
||||
@@ -1265,14 +1271,21 @@ var artplayerPluginDanmuku = (function() {
|
||||
const y = point[1];
|
||||
point[1] = y * (y > yMid ? 1 + options.scale : 1 - options.scale) + options.minHeight;
|
||||
}
|
||||
const automatic = !hasCustomPoints && !Number.isFinite(configured.yMin) && !Number.isFinite(configured.yMax);
|
||||
let peak = 0;
|
||||
for (const point of points) peak = Math.max(peak, point[1]);
|
||||
const fitted = automatic && peak > defaults.yMax / 4;
|
||||
if (fitted)
|
||||
options.yMax = peak * 4;
|
||||
const boundY = (value) => fitted ? Math.min(height, Math.max(height * 0.75, value)) : value;
|
||||
const controlPoint = (current, previous, next, reverse) => {
|
||||
const geometry = line(previous || current, next || current);
|
||||
const flat = map(Math.cos(geometry.angle) * options.flattening, 0, 1, 1, 0);
|
||||
const angle = geometry.angle * flat + (reverse ? Math.PI : 0);
|
||||
const length = geometry.length * options.smoothing;
|
||||
return [current[0] + Math.cos(angle) * length, current[1] + Math.sin(angle) * length];
|
||||
return [current[0] + Math.cos(angle) * length, boundY(current[1] + Math.sin(angle) * length)];
|
||||
};
|
||||
const positions = points.map((point) => [map(point[0], options.xMin, options.xMax, 0, width), map(point[1], options.yMin, options.yMax, height, 0)]);
|
||||
const positions = points.map((point) => [map(point[0], options.xMin, options.xMax, 0, width), boundY(map(point[1], options.yMin, options.yMax, height, 0))]);
|
||||
if (!positions.every((point) => point.every(Number.isFinite)))
|
||||
return null;
|
||||
const path = positions.map((point, index, all) => {
|
||||
@@ -1299,8 +1312,9 @@ var artplayerPluginDanmuku = (function() {
|
||||
let closed = false;
|
||||
const active = () => !closed && !art.isDestroy;
|
||||
function listen(name, callback) {
|
||||
subscriptions.push([name, callback]);
|
||||
art.on(name, callback);
|
||||
const listener = callback;
|
||||
subscriptions.push([name, listener]);
|
||||
art.on(name, listener);
|
||||
}
|
||||
function dispose(removeControl) {
|
||||
if (closed)
|
||||
@@ -1338,18 +1352,19 @@ var artplayerPluginDanmuku = (function() {
|
||||
return;
|
||||
start = null;
|
||||
stop = null;
|
||||
element.innerHTML = "";
|
||||
const target = element;
|
||||
target.innerHTML = "";
|
||||
if (art.option.isLive)
|
||||
return;
|
||||
const shape = heatmapGeometry({ width: element.offsetWidth, height: element.offsetHeight, duration: art.duration, queue: danmuku.queue, option, points });
|
||||
const shape = heatmapGeometry({ width: target.offsetWidth, height: target.offsetHeight, duration: art.duration, queue: danmuku.queue, option, points });
|
||||
if (!shape || !active())
|
||||
return;
|
||||
const document2 = element.ownerDocument;
|
||||
const document2 = target.ownerDocument;
|
||||
if (!gradient)
|
||||
gradient = document2 ? "heatmap-solids" : `heatmap-solids-${++nextGradient}`;
|
||||
while (document2?.getElementById(gradient))
|
||||
gradient = `heatmap-solids-${++nextGradient}`;
|
||||
element.innerHTML = `
|
||||
target.innerHTML = `
|
||||
<svg viewBox="0 0 ${shape.width} ${shape.height}">
|
||||
<defs>
|
||||
<linearGradient id="${gradient}" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
@@ -1362,8 +1377,8 @@ var artplayerPluginDanmuku = (function() {
|
||||
<path fill="url(#${gradient})" d="${shape.path}"></path>
|
||||
</svg>
|
||||
`;
|
||||
start = query("#heatmap-start", element);
|
||||
stop = query("#heatmap-stop", element);
|
||||
start = query("#heatmap-start", target);
|
||||
stop = query("#heatmap-stop", target);
|
||||
progress(art.played);
|
||||
}
|
||||
function update(points) {
|
||||
@@ -1443,7 +1458,8 @@ var artplayerPluginDanmuku = (function() {
|
||||
dispose();
|
||||
else this.disposers.add(dispose);
|
||||
}
|
||||
write(target, key, value, apply = (value2) => target[key] = value2) {
|
||||
write(host, key, value, apply = (value2) => host[key] = value2) {
|
||||
const target = host;
|
||||
if (!this.active)
|
||||
return;
|
||||
const priority = () => typeof target.getPropertyPriority === "function" ? target.getPropertyPriority(key) : void 0;
|
||||
@@ -1834,16 +1850,17 @@ var artplayerPluginDanmuku = (function() {
|
||||
if (typeof document !== "undefined") {
|
||||
const id = "artplayer-plugin-danmuku";
|
||||
const pending = /* @__PURE__ */ Symbol.for("artplayer-plugin-danmuku.pending-style");
|
||||
let $style2 = document.getElementById(id) || document[pending];
|
||||
const styleDocument = document;
|
||||
let $style2 = document.getElementById(id) || styleDocument[pending];
|
||||
if (!$style2) {
|
||||
$style2 = document.createElement("style");
|
||||
$style2.id = id;
|
||||
if (document.readyState === "loading") {
|
||||
document[pending] = $style2;
|
||||
styleDocument[pending] = $style2;
|
||||
const ready = () => {
|
||||
document.removeEventListener("DOMContentLoaded", ready);
|
||||
if (document[pending] === $style2)
|
||||
delete document[pending];
|
||||
if (styleDocument[pending] === $style2)
|
||||
delete styleDocument[pending];
|
||||
const existing = document.getElementById(id);
|
||||
if (existing)
|
||||
existing.textContent = $style2.textContent;
|
||||
|
||||
Reference in new issue
Block a user