chore: Refactor artplayerPluginDanmuku plugin and add artplayerPluginChromecast plugin

This commit is contained in:
Harvey Zack committed 2024-05-28 08:45:43 +08:00
1 parent 9ca560fd05
commit 313b6ae54d
5 files changed
+111 -45

No files matched your search

+2 -3
View File
@@ -8,14 +8,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [5.1.2] - 2024-6-1
- 重构 `artplayerPluginDanmuku` 插件
- 新增 `artplayerPluginChromecast` 插件
- 添加 `fullscreenError` 事件
- 添加 `supportsFlex` 工具函数
- 优化双击事件: [#728](https://github.com/zhw2590582/ArtPlayer/pull/728)
- 修复 `thumbnails` 延迟显示问题
- 新增 `artplayerPluginChromecast` 插件
- 新增 `art.plugins.lock.state = true/false`, 用于手动控制 `lock` 状态
- 当鼠标在控制栏上,或者打开了设置面板,控制栏不再自动隐藏
- 重构 `artplayerPluginDanmuku` 插件
## [5.1.1] - 2024-1-11
@@ -202,7 +202,15 @@ class Danmuku {
this.isStop = false; // 是否停止
this.isHide = false; // 是否隐藏
this.timer = null; // 定时器
this.config(option); // 动态配置
// 弹幕状态池
this.states = {
wait: [],
ready: [],
emit: [],
stop: []
};
// 初始化配置
this.config(option);
// 创建 Web Worker, 用于计算弹幕的 top 值
this.worker = new Worker(URL.createObjectURL(new Blob([
(0, _workerDefault.default)
@@ -211,6 +219,7 @@ class Danmuku {
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
this.reset = this.reset.bind(this);
this.resize = this.resize.bind(this);
this.destroy = this.destroy.bind(this);
// 监听事件
art.on("video:play", this.start);
@@ -218,7 +227,7 @@ class Danmuku {
art.on("video:pause", this.stop);
art.on("video:waiting", this.stop);
art.on("destroy", this.destroy);
art.on("resize", this.reset);
art.on("resize", this.resize);
// 开始加载弹幕
this.load();
}
@@ -346,12 +355,15 @@ class Danmuku {
// 获取准备好发送的弹幕:有的是ready状态(如之前因为弹幕太多而暂停发送的弹幕),有的是wait状态
get readys() {
const { currentTime } = this.art;
return this.queue.filter((danmu)=>{
return danmu.$state === "ready" || danmu.$state === "wait" && currentTime + 0.1 >= danmu.time && danmu.time >= currentTime - 0.1;
const result = [];
this.filter("ready", (danmu)=>result.push(danmu));
this.filter("wait", (danmu)=>{
if (currentTime + 0.1 >= danmu.time && danmu.time >= currentTime - 0.1) result.push(danmu);
});
return result;
}
// 获取正在发送的弹幕,用于计算下一个弹幕的top值
get emits() {
// 可见的弹幕的数据,用于计算下一个弹幕的top值
get visibles() {
const result = [];
const { clientWidth } = this.$player;
const clientLeft = this.getLeft(this.$player);
@@ -390,8 +402,6 @@ class Danmuku {
this.$danmuku.innerText = ""; // 清空弹幕层
this.danmus.forEach((danmu)=>this.emit(danmu)); // 逐个验证原始弹幕并转换为实际弹幕
this.art.emit("artplayerPluginDanmuku:loaded", this.queue);
// TODO: 按时间从小到大排序,用于减少弹幕的遍历次数,待优化...
// this.queue = this.queue.sort((a, b) => a.time - b.time);
} catch (error) {
this.art.emit("artplayerPluginDanmuku:error", error);
throw error;
@@ -431,10 +441,11 @@ class Danmuku {
].includes(danmu.mode)) return this;
// 自定义弹幕过滤函数
if (!this.option.filter(danmu)) return this;
// 转换为wait状态
this.setState(danmu, "wait");
// 添加到实际弹幕队列
this.queue.push({
...danmu,
$state: "wait",
$ref: null,
$restTime: 0,
$lastStartTime: 0
@@ -485,13 +496,24 @@ class Danmuku {
};
});
}
// 根据状态,获取弹幕队列中的弹幕
// 根据状态获取弹幕
filter(state, callback) {
return this.queue.filter((danmu)=>danmu.$state === state).map(callback);
const danmus = this.states[state] || [];
for(let index = 0; index < danmus.length; index++)callback(danmus[index]);
return danmus;
}
// 设置弹幕状态
setState(danmu, state) {
// 从原状态池中删除
if (danmu.$state) this.states[danmu.$state] = this.states[danmu.$state].filter((item)=>item !== danmu);
// 设置新状态
danmu.$state = state;
// 添加到新状态池中
this.states[state].push(danmu);
}
// 重置弹幕到wait状态,回收弹幕DOM节点
makeWait(danmu) {
danmu.$state = "wait";
this.setState(danmu, "wait");
if (danmu.$ref) {
danmu.$ref.style.cssText = Danmuku.cssText;
this.$refs.push(danmu.$ref);
@@ -546,7 +568,7 @@ class Danmuku {
height: danmu.$ref.clientHeight,
speed: (clientWidth + danmu.$ref.clientWidth) / danmu.$restTime
},
emits: this.emits,
visibles: this.visibles,
antiOverlap: this.option.antiOverlap,
clientWidth: clientWidth,
clientHeight: clientHeight,
@@ -555,7 +577,7 @@ class Danmuku {
});
if (danmu.$ref) {
if (!this.isStop && top !== undefined) {
danmu.$state = "emit"; // 转换为emit状态
this.setState(danmu, "emit"); // 转换为emit状态
danmu.$ref.style.visibility = "visible";
danmu.$ref.dataset.mode = danmu.mode; // CSS控制模式的显示和隐藏
this.art.emit("artplayerPluginDanmuku:visible", danmu);
@@ -581,7 +603,7 @@ class Danmuku {
}
} else {
// 假如弹幕已经停止或者没有 top 值,则重置弹幕为ready状态,回收弹幕DOM节点,等待下次发送
danmu.$state = "ready";
this.setState(danmu, "ready");
this.$refs.push(danmu.$ref);
danmu.$ref = null;
}
@@ -594,11 +616,17 @@ class Danmuku {
});
return this;
}
// 重置正在显示的弹幕
resize() {
this.filter("emit", (danmu)=>{
//
});
}
// 继续弹幕
continue() {
const { clientWidth } = this.$player;
this.filter("stop", (danmu)=>{
danmu.$state = "emit"; // 转换为emit状态
this.setState(danmu, "emit"); // 转换为emit状态
danmu.$lastStartTime = Date.now();
switch(danmu.mode){
// 继续滚动的弹幕
@@ -619,7 +647,7 @@ class Danmuku {
suspend() {
const { clientWidth } = this.$player;
this.filter("emit", (danmu)=>{
danmu.$state = "stop"; // 转换为stop状态
this.setState(danmu, "stop"); // 转换为stop状态
switch(danmu.mode){
// 停止滚动的弹幕
case 0:
@@ -765,7 +793,7 @@ exports.export = function(dest, destName, get) {
};
},{}],"el0Wt":[function(require,module,exports) {
module.exports = "// modules are defined as an array\n// [ module function, map of requires ]\n//\n// map of requires is short require name -> numeric require\n//\n// anything defined in a previous bundle is accessed via the\n// orig method which is the require for previous bundles\n\n(function (modules, entry, mainEntry, parcelRequireName, globalName) {\n /* eslint-disable no-undef */\n var globalObject =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n /* eslint-enable no-undef */\n\n // Save the require from previous bundle to this closure if any\n var previousRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n\n var cache = previousRequire.cache || {};\n // Do not use `require` to prevent Webpack from trying to bundle this call\n var nodeRequire =\n typeof module !== 'undefined' &&\n typeof module.require === 'function' &&\n module.require.bind(module);\n\n function newRequire(name, jumped) {\n if (!cache[name]) {\n if (!modules[name]) {\n // if we cannot find the module within our internal map or\n // cache jump to the current global require ie. the last bundle\n // that was added to the page.\n var currentRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n if (!jumped && currentRequire) {\n return currentRequire(name, true);\n }\n\n // If there are other bundles on this page the require from the\n // previous one is saved to 'previousRequire'. Repeat this as\n // many times as there are bundles until the module is found or\n // we exhaust the require chain.\n if (previousRequire) {\n return previousRequire(name, true);\n }\n\n // Try the node require function if it exists.\n if (nodeRequire && typeof name === 'string') {\n return nodeRequire(name);\n }\n\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n localRequire.resolve = resolve;\n localRequire.cache = {};\n\n var module = (cache[name] = new newRequire.Module(name));\n\n modules[name][0].call(\n module.exports,\n localRequire,\n module,\n module.exports,\n this\n );\n }\n\n return cache[name].exports;\n\n function localRequire(x) {\n var res = localRequire.resolve(x);\n return res === false ? {} : newRequire(res);\n }\n\n function resolve(x) {\n var id = modules[name][1][x];\n return id != null ? id : x;\n }\n }\n\n function Module(moduleName) {\n this.id = moduleName;\n this.bundle = newRequire;\n this.exports = {};\n }\n\n newRequire.isParcelRequire = true;\n newRequire.Module = Module;\n newRequire.modules = modules;\n newRequire.cache = cache;\n newRequire.parent = previousRequire;\n newRequire.register = function (id, exports) {\n modules[id] = [\n function (require, module) {\n module.exports = exports;\n },\n {},\n ];\n };\n\n Object.defineProperty(newRequire, 'root', {\n get: function () {\n return globalObject[parcelRequireName];\n },\n });\n\n globalObject[parcelRequireName] = newRequire;\n\n for (var i = 0; i < entry.length; i++) {\n newRequire(entry[i]);\n }\n\n if (mainEntry) {\n // Expose entry point to Node, AMD or browser globals\n // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js\n var mainExports = newRequire(mainEntry);\n\n // CommonJS\n if (typeof exports === 'object' && typeof module !== 'undefined') {\n module.exports = mainExports;\n\n // RequireJS\n } else if (typeof define === 'function' && define.amd) {\n define(function () {\n return mainExports;\n });\n\n // <script>\n } else if (globalName) {\n this[globalName] = mainExports;\n }\n }\n})({\"fHwfs\":[function(require,module,exports) {\nfunction getDanmuTop({ target, emits, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {\n // 弹幕最大高度\n const maxTop = clientHeight - marginBottom;\n // 过滤同模式的弹幕,即每种模式各不影响\n const danmus = emits.filter((item)=>item.mode === target.mode && item.top <= maxTop).sort((prev, next)=>prev.top - next.top);\n // 如果没有同模式的弹幕,直接返回\n if (danmus.length === 0) {\n if (target.mode === 2) return maxTop - target.height;\n else return marginTop;\n }\n // 上下各加一个虚拟弹幕,方便计算\n danmus.unshift({\n type: \"top\",\n top: 0,\n left: 0,\n right: 0,\n height: margiLine truncated
module.exports = "// modules are defined as an array\n// [ module function, map of requires ]\n//\n// map of requires is short require name -> numeric require\n//\n// anything defined in a previous bundle is accessed via the\n// orig method which is the require for previous bundles\n\n(function (modules, entry, mainEntry, parcelRequireName, globalName) {\n /* eslint-disable no-undef */\n var globalObject =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n /* eslint-enable no-undef */\n\n // Save the require from previous bundle to this closure if any\n var previousRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n\n var cache = previousRequire.cache || {};\n // Do not use `require` to prevent Webpack from trying to bundle this call\n var nodeRequire =\n typeof module !== 'undefined' &&\n typeof module.require === 'function' &&\n module.require.bind(module);\n\n function newRequire(name, jumped) {\n if (!cache[name]) {\n if (!modules[name]) {\n // if we cannot find the module within our internal map or\n // cache jump to the current global require ie. the last bundle\n // that was added to the page.\n var currentRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n if (!jumped && currentRequire) {\n return currentRequire(name, true);\n }\n\n // If there are other bundles on this page the require from the\n // previous one is saved to 'previousRequire'. Repeat this as\n // many times as there are bundles until the module is found or\n // we exhaust the require chain.\n if (previousRequire) {\n return previousRequire(name, true);\n }\n\n // Try the node require function if it exists.\n if (nodeRequire && typeof name === 'string') {\n return nodeRequire(name);\n }\n\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n localRequire.resolve = resolve;\n localRequire.cache = {};\n\n var module = (cache[name] = new newRequire.Module(name));\n\n modules[name][0].call(\n module.exports,\n localRequire,\n module,\n module.exports,\n this\n );\n }\n\n return cache[name].exports;\n\n function localRequire(x) {\n var res = localRequire.resolve(x);\n return res === false ? {} : newRequire(res);\n }\n\n function resolve(x) {\n var id = modules[name][1][x];\n return id != null ? id : x;\n }\n }\n\n function Module(moduleName) {\n this.id = moduleName;\n this.bundle = newRequire;\n this.exports = {};\n }\n\n newRequire.isParcelRequire = true;\n newRequire.Module = Module;\n newRequire.modules = modules;\n newRequire.cache = cache;\n newRequire.parent = previousRequire;\n newRequire.register = function (id, exports) {\n modules[id] = [\n function (require, module) {\n module.exports = exports;\n },\n {},\n ];\n };\n\n Object.defineProperty(newRequire, 'root', {\n get: function () {\n return globalObject[parcelRequireName];\n },\n });\n\n globalObject[parcelRequireName] = newRequire;\n\n for (var i = 0; i < entry.length; i++) {\n newRequire(entry[i]);\n }\n\n if (mainEntry) {\n // Expose entry point to Node, AMD or browser globals\n // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js\n var mainExports = newRequire(mainEntry);\n\n // CommonJS\n if (typeof exports === 'object' && typeof module !== 'undefined') {\n module.exports = mainExports;\n\n // RequireJS\n } else if (typeof define === 'function' && define.amd) {\n define(function () {\n return mainExports;\n });\n\n // <script>\n } else if (globalName) {\n this[globalName] = mainExports;\n }\n }\n})({\"fHwfs\":[function(require,module,exports) {\nfunction getDanmuTop({ target, visibles, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {\n // 弹幕最大高度\n const maxTop = clientHeight - marginBottom;\n // 过滤同模式的弹幕,即每种模式各不影响\n const danmus = visibles.filter((item)=>item.mode === target.mode && item.top <= maxTop).sort((prev, next)=>prev.top - next.top);\n // 如果没有同模式的弹幕,直接返回\n if (danmus.length === 0) {\n if (target.mode === 2) return maxTop - target.height;\n else return marginTop;\n }\n // 上下各加一个虚拟弹幕,方便计算\n danmus.unshift({\n type: \"top\",\n top: 0,\n left: 0,\n right: 0,\n height:Line truncated
},{}],"cI0ih":[function(require,module,exports) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
@@ -1 +1 @@
{"mappings":"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 truncated
{"mappings":"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 truncated
@@ -18,7 +18,17 @@ export default class Danmuku {
this.isStop = false; // 是否停止
this.isHide = false; // 是否隐藏
this.timer = null; // 定时器
this.config(option); // 动态配置
// 弹幕状态池
this.states = {
wait: [],
ready: [],
emit: [],
stop: [],
};
// 初始化配置
this.config(option);
// 创建 Web Worker, 用于计算弹幕的 top 值
this.worker = new Worker(URL.createObjectURL(new Blob([workerText])));
@@ -27,6 +37,7 @@ export default class Danmuku {
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
this.reset = this.reset.bind(this);
this.resize = this.resize.bind(this);
this.destroy = this.destroy.bind(this);
// 监听事件
@@ -35,7 +46,7 @@ export default class Danmuku {
art.on('video:pause', this.stop);
art.on('video:waiting', this.stop);
art.on('destroy', this.destroy);
art.on('resize', this.reset);
art.on('resize', this.resize);
// 开始加载弹幕
this.load();
@@ -182,16 +193,20 @@ export default class Danmuku {
// 获取准备好发送的弹幕:有的是ready状态(如之前因为弹幕太多而暂停发送的弹幕),有的是wait状态
get readys() {
const { currentTime } = this.art;
return this.queue.filter((danmu) => {
return (
danmu.$state === 'ready' ||
(danmu.$state === 'wait' && currentTime + 0.1 >= danmu.time && danmu.time >= currentTime - 0.1)
);
const result = [];
this.filter('ready', (danmu) => result.push(danmu));
this.filter('wait', (danmu) => {
if (currentTime + 0.1 >= danmu.time && danmu.time >= currentTime - 0.1) {
result.push(danmu);
}
});
return result;
}
// 获取正在发送的弹幕,用于计算下一个弹幕的top值
get emits() {
// 可见的弹幕的数据,用于计算下一个弹幕的top值
get visibles() {
const result = [];
const { clientWidth } = this.$player;
const clientLeft = this.getLeft(this.$player);
@@ -243,9 +258,6 @@ export default class Danmuku {
this.$danmuku.innerText = ''; // 清空弹幕层
this.danmus.forEach((danmu) => this.emit(danmu)); // 逐个验证原始弹幕并转换为实际弹幕
this.art.emit('artplayerPluginDanmuku:loaded', this.queue);
// TODO: 按时间从小到大排序,用于减少弹幕的遍历次数,待优化...
// this.queue = this.queue.sort((a, b) => a.time - b.time);
} catch (error) {
this.art.emit('artplayerPluginDanmuku:error', error);
throw error;
@@ -304,10 +316,12 @@ export default class Danmuku {
// 自定义弹幕过滤函数
if (!this.option.filter(danmu)) return this;
// 转换为wait状态
this.setState(danmu, 'wait');
// 添加到实际弹幕队列
this.queue.push({
...danmu,
$state: 'wait', // 弹幕状态
$ref: null, // 弹幕 DOM 节点
$restTime: 0, // 弹幕剩余时间
$lastStartTime: 0, // 弹幕上次开始时间
@@ -381,14 +395,32 @@ export default class Danmuku {
});
}
// 根据状态,获取弹幕队列中的弹幕
// 根据状态获取弹幕
filter(state, callback) {
return this.queue.filter((danmu) => danmu.$state === state).map(callback);
const danmus = this.states[state] || [];
for (let index = 0; index < danmus.length; index++) {
callback(danmus[index]);
}
return danmus;
}
// 设置弹幕状态
setState(danmu, state) {
// 从原状态池中删除
if (danmu.$state) {
this.states[danmu.$state] = this.states[danmu.$state].filter((item) => item !== danmu);
}
// 设置新状态
danmu.$state = state;
// 添加到新状态池中
this.states[state].push(danmu);
}
// 重置弹幕到wait状态,回收弹幕DOM节点
makeWait(danmu) {
danmu.$state = 'wait';
this.setState(danmu, 'wait');
if (danmu.$ref) {
danmu.$ref.style.cssText = Danmuku.cssText;
this.$refs.push(danmu.$ref);
@@ -463,7 +495,7 @@ export default class Danmuku {
height: danmu.$ref.clientHeight,
speed: (clientWidth + danmu.$ref.clientWidth) / danmu.$restTime,
}, // 当前弹幕信息
emits: this.emits, // 正在发送的其它弹幕
visibles: this.visibles, // 可见的弹幕的数据
antiOverlap: this.option.antiOverlap,
clientWidth: clientWidth,
clientHeight: clientHeight,
@@ -473,7 +505,7 @@ export default class Danmuku {
if (danmu.$ref) {
if (!this.isStop && top !== undefined) {
danmu.$state = 'emit'; // 转换为emit状态
this.setState(danmu, 'emit'); // 转换为emit状态
danmu.$ref.style.visibility = 'visible';
danmu.$ref.dataset.mode = danmu.mode; // CSS控制模式的显示和隐藏
this.art.emit('artplayerPluginDanmuku:visible', danmu);
@@ -499,7 +531,7 @@ export default class Danmuku {
}
} else {
// 假如弹幕已经停止或者没有 top 值,则重置弹幕为ready状态,回收弹幕DOM节点,等待下次发送
danmu.$state = 'ready';
this.setState(danmu, 'ready');
this.$refs.push(danmu.$ref);
danmu.$ref = null;
}
@@ -516,11 +548,18 @@ export default class Danmuku {
return this;
}
// 重置正在显示的弹幕
resize() {
this.filter('emit', (danmu) => {
//
});
}
// 继续弹幕
continue() {
const { clientWidth } = this.$player;
this.filter('stop', (danmu) => {
danmu.$state = 'emit'; // 转换为emit状态
this.setState(danmu, 'emit'); // 转换为emit状态
danmu.$lastStartTime = Date.now();
switch (danmu.mode) {
// 继续滚动的弹幕
@@ -542,7 +581,7 @@ export default class Danmuku {
suspend() {
const { clientWidth } = this.$player;
this.filter('emit', (danmu) => {
danmu.$state = 'stop'; // 转换为stop状态
this.setState(danmu, 'stop'); // 转换为stop状态
switch (danmu.mode) {
// 停止滚动的弹幕
case 0: {
@@ -1,9 +1,9 @@
function getDanmuTop({ target, emits, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {
function getDanmuTop({ target, visibles, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {
// 弹幕最大高度
const maxTop = clientHeight - marginBottom;
// 过滤同模式的弹幕,即每种模式各不影响
const danmus = emits
const danmus = visibles
.filter((item) => item.mode === target.mode && item.top <= maxTop)
.sort((prev, next) => prev.top - next.top);