feat: 集成edu-core模块并重构课程详情页视频播放

- 添加edu-core本地依赖,用于视频播放组件
- 重构课程详情页,使用CourseVideo组件替换原有视频播放逻辑
- 优化课程列表页布局和样式,修复边框单位问题
- 更新manifest.json支持多方向屏幕旋转
This commit is contained in:
2026-02-09 10:29:59 +08:00
parent 671b7eb63d
commit 0e900d19be
33 changed files with 11533 additions and 98 deletions

View File

@@ -0,0 +1,671 @@
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var YbDanmu = /*#__PURE__*/function () {
function YbDanmu(container, data) {
var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
_classCallCheck(this, YbDanmu);
this.container = typeof container == 'string' ? document.querySelector(container) : container;
this.config = _objectSpread(_objectSpread({}, YbDanmu.DEFAULT_CONFIG), config);
this.data = data;
this.filter = new YbDanmuFilter(this.config.filter); //过滤规则
this.list = this._filterData(data);
this.runline = []; //正在跑动的弹幕列表
this.canvas = null; //canvas元素
this.ctx = null; //canvas实例
this.paused = true; //是否暂停
this.currentTime = 0; //当前时间轴
this._animation = null; //动画实例
}
return _createClass(YbDanmu, [{
key: "load",
value:
//加载弹幕
function load() {
if (this.container) {
var canvas = document.createElement('CANVAS');
this.container.appendChild(canvas);
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.updateSize();
}
}
//卸载弹幕
}, {
key: "unload",
value: function unload() {
this._clearAnimationFrame();
this.list = [];
this.runline = [];
if (this.ctx) this.ctx = null;
if (this.canvas) {
this.canvas.remove();
this.canvas = null;
}
}
//更新数据
}, {
key: "setData",
value: function setData(data) {
this.data = data;
this.reset();
}
//动态配置
}, {
key: "setConfig",
value: function setConfig(key, value) {
this.config[key] = value;
}
//播放弹幕
}, {
key: "play",
value: function play() {
this.paused = false;
this._render();
}
//暂停弹幕
}, {
key: "pause",
value: function pause() {
this._clearAnimationFrame();
this.paused = true;
}
//跳转弹幕
}, {
key: "seek",
value: function seek(time) {
this.currentTime = time;
this.reset();
}
//更新时间轴(需要外部更新时间轴否则弹幕不会运行)
}, {
key: "time",
value: function time(_time) {
var _this = this;
//计算本次更新时间和上次时间的时间差
var diffrenece = _time - this.currentTime;
//记录新时间
this.currentTime = _time;
//新列表
var newList = [];
//跑动列表
var runline = [];
//循环弹幕列表
this.list.forEach(function (danmu) {
//当前时间减去弹幕显示时间
var range = _this.getCurrentTime() - danmu.time;
//获取当前时间和上次时间的时间差以内的弹幕
if (range >= 0 && range < Math.abs(diffrenece)) runline.push(danmu);
//记录不在范围内的弹幕
else newList.push(danmu);
});
//去掉已经渲染的弹幕
this.list = newList;
//计算需要渲染弹幕的布局
for (var i = 0; i < runline.length; i++) {
var bar = this._layout(runline[i]);
if (bar) this.runline.push(bar);
}
//排序弹幕
this.runline.sort(function (a, b) {
return a.time - b.time;
});
}
//清空画布
}, {
key: "clear",
value: function clear() {
this.ctx && this.ctx.clearRect(0, 0, this.canvas.offsetWidth, this.canvas.offsetHeight);
}
//显示弹幕舞台
}, {
key: "show",
value: function show() {
this.container.style.visibility = 'visible';
}
//隐藏弹幕舞台
}, {
key: "hide",
value: function hide() {
this.container.style.visibility = 'hidden';
}
//更新尺寸
}, {
key: "updateSize",
value: function updateSize() {
var width = this.container.offsetWidth;
var height = this.container.offsetHeight;
var dpr = this.config.accuracy == 'auto' ? window.devicePixelRatio : this.config.accuracy;
this.canvas.width = width * dpr;
this.canvas.height = height * dpr;
this.canvas.style.width = width;
this.canvas.style.height = height;
this.ctx.scale(dpr, dpr);
}
//重置数据和画布
}, {
key: "reset",
value: function reset() {
var _this2 = this;
this.clear();
this.list = this._filterData(this.data);
this.runline = [];
var duration = this.canvas.offsetWidth / (this.config.speed * this.config.playbackRate) / 60; //滚动周期除以60是因为为大概每秒60帧根据滚动周期去获取可能出现在屏幕上的弹幕
var newList = [];
var runline = [];
this.list.forEach(function (danmu) {
var range = _this2.getCurrentTime() - danmu.time;
//重置数据的时候,考虑到播放进度可能在中间,未避免弹幕丢失,将时间误差控制在滚动周期以内
if (range >= 0 && range < duration) runline.push(danmu);
//记录不在范围内的弹幕
else newList.push(danmu);
});
//去掉已经渲染的弹幕
this.list = newList;
//计算渲染弹幕的布局
for (var i = 0; i < runline.length; i++) {
var bar = this._layout(runline[i]);
if (bar) this.runline.push(bar);
}
this.runline.sort(function (a, b) {
return a.time - b.time;
}); //排序弹幕
}
}, {
key: "refresh",
value: function refresh() {
this.updateSize();
this.reset();
}
//弹幕是否正在显示
}, {
key: "getVisible",
value: function getVisible() {
var _this$container$style;
return this.container ? ((_this$container$style = this.container.style) === null || _this$container$style === void 0 ? void 0 : _this$container$style.visibility) == 'visible' : false;
}
//获取时间进度
}, {
key: "getCurrentTime",
value: function getCurrentTime() {
return this.currentTime + this.config.timeDiffrence; //加上时间差
}
/**
* 发送弹幕
* @param {Object} danmu 弹幕数据
* @param {Boolean}border 使用边框
*/
}, {
key: "send",
value: function send(danmu, border) {
this.data.push(danmu);
this.runline.push(this._layout(_objectSpread(_objectSpread({}, danmu), {}, {
time: danmu.time + this.config.timeDiffrence
}), border, true)); //强制显示弹幕
}
//插入弹幕数据,但不会渲染
}, {
key: "insert",
value: function insert(danmu) {
this.data.push(danmu);
this.list.push(danmu);
}
//渲染弹幕
}, {
key: "_render",
value: function _render() {
var _this3 = this;
this._clearAnimationFrame();
if (this.paused) return;
if (this.runline.length) {
this.clear();
for (var i = 0; i < this.runline.length; i++) {
var b = this.runline[i];
//移除渲染完毕的弹幕
if (b.left + b.width <= 0 || b.boxWidth <= 0) {
this.runline.splice(i, 1);
i--;
continue;
}
// b.speed = this._detectionBump(b);//碰撞检测,保留位置,可能不需要
var speed = (this.config.speed + b.speed) * this.config.playbackRate; //弹幕随机的速度加上默认设置速度再乘以倍速,才是真正移动的速度
if (b.mode == 1 || !b.mode) b.left -= speed; //滚动弹幕将x轴位置减去速度实现滚动动画
else b.boxWidth -= speed; //顶端和底端弹幕,将记录的画布宽度减去速度,实现渲染时长
//非滚动弹幕当boxWidth大于画布宽度时则不绘制避免弹幕提前出现
if (b.mode == 1 || !b.mode || b.boxWidth <= this.canvas.offsetWidth) this._drawText(b);
}
}
this._animation = window.requestAnimationFrame(function () {
return _this3._render();
});
}
/**
* 计算弹幕布局
* @param { Object|String } danmu 弹幕对象
* @param {Boolean} border 是否使用边框
* @param {Boolean} force 是否强制显示
*/
}, {
key: "_layout",
value: function _layout(danmu, border, force) {
var ctx = this.ctx;
var canvas = this.canvas;
var config = this.config;
var boxWidth = canvas.offsetWidth;
var fontSize = danmu.fontSize || config.fontSize;
var fontFamily = danmu.fontFamily || config.fontFamily;
var fontScale = config.fontScale;
var color = danmu.color || config.color;
var mode = danmu.mode || 1;
var text = danmu.text;
var time = danmu.time;
ctx.font = "".concat(fontSize * fontScale, "px ").concat(fontFamily); //设置字体大小和样式
var width = Math.ceil(ctx.measureText(text).width); //测算文本宽度
var speed = mode == 1 ? Math.random() * 0.1 : 0; //随机移动速度(弹幕一帧移动的距离,加上随机数,可以让弹幕滚动更加有层次感)
var offset = (this.getCurrentTime() - time) * 60 * (config.speed + speed); //根据弹幕出现时间和当前时间轴的时间差,计算弹幕的初始偏移值
var left = mode == 1 ? boxWidth - offset : boxWidth / 2 - width / 2; //获取弹幕x轴位置
var track = this._getTrack(fontSize, mode, offset, force); //获取弹幕y轴位置
var top = track.top;
if (top > -1) {
return {
mode: mode,
text: text,
time: time,
fontSize: fontSize,
color: color,
top: top,
left: left,
speed: track.isOverlap ? speed + 2 + Math.random() * 0.5 : speed,
//如果是重叠的弹幕则加快速度,避免一直重叠,这样观感不好
width: width,
boxWidth: boxWidth - offset,
//顶部和底部弹幕的显示时间根据舞台宽度和移动速度决定
border: border //自己发送的弹幕需要加上边框,作区别显示
};
}
return false;
}
/**
* 绘制文字
* @param {Object} danmu 弹幕对象
* @param {String} mode 弹幕模式 1-滚动 4-底部 5-顶部
*/
}, {
key: "_drawText",
value: function _drawText(danmu) {
var mode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var ctx = this.ctx;
var config = this.config;
if (ctx) {
ctx.beginPath();
var fontSize = danmu.fontSize || config.fontSize;
var fontFamily = danmu.fontFamily || config.fontFamily;
var color = danmu.color || config.color;
var opacity = config.opacity;
var fontScale = config.fontScale;
var newFontSize = fontSize * fontScale;
ctx.font = "".concat(fontSize * fontScale, "px ").concat(fontFamily);
ctx.strokeStyle = YbDanmu.colorToRgba(YbDanmu.getStrokeColor(color), opacity);
ctx.strokeText(danmu.text, danmu.left, danmu.top);
ctx.fillStyle = YbDanmu.colorToRgba(color, opacity);
ctx.fillText(danmu.text, danmu.left, danmu.top);
if (danmu.border) {
//如果带边框
ctx.strokeStyle = color; //边框颜色
ctx.lineWidth = 2; //边框宽度
ctx.strokeRect(danmu.left, danmu.top - newFontSize, danmu.width, newFontSize + config.lineGap); //绘制边框
}
ctx.closePath();
}
}
/**
* 计算弹幕应该放在哪条轨道
* @param fontSize弹幕字体大小
* @param mode弹幕模式1-滚动 4-底部 5-顶部
* @param offset弹幕初始x轴位置偏差值
* @param force是否强制显示用于弹幕发送
*/
}, {
key: "_getTrack",
value: function _getTrack(fontSize) {
var mode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var force = arguments.length > 3 ? arguments[3] : undefined;
//canvas绘制文字x,y坐标是按文字左下角计算预留30px
var canvas = this.canvas;
var isOverlap = false; //是否重叠
var nowTop = -1; //最终返回的顶部距离
var minLen = -1; //最小弹幕数量
var minTop = -1; //最小弹幕数量轨道
var boxWidth = canvas.offsetWidth;
var boxHeight = canvas.offsetHeight;
var config = this.config;
var lineGap = config.lineGap;
var top = config.top;
var bottom = config.bottom;
var fontScale = config.fontScale;
var newFontSize = fontSize * fontScale;
var reserve = 5; //画布预留位置(给画布底部流出一段距离)不预留可能导致最后一个轨道的弹幕显示不全
var trackLen = Math.floor((boxHeight - top - bottom) / (newFontSize + lineGap)); //计算轨道数量
var tracks = [];
if (mode == 4) {
//弹幕模式为底端,从底部开始加载,所以要用画布高度减去轨道高度,才是底端弹幕渲染的轨道高度
for (var i = 0; i < trackLen; i++) tracks.push(boxHeight - (i * newFontSize + i * lineGap + top + reserve)); //排列轨道
} else {
for (var _i = 0; _i < trackLen; _i++) tracks.push((_i + 1) * newFontSize + _i * lineGap + top); //排列轨道
}
for (var _i2 = 0; _i2 < tracks.length; _i2++) {
var trackTop = tracks[_i2];
//当前轨道上有多少条弹幕
var danmus = this.runline.filter(function (danmu) {
return danmu.top < trackTop + newFontSize && danmu.fontSize * fontScale + danmu.top > trackTop && danmu.mode == mode;
});
if (danmus.length < minLen || minLen == -1) {
//获取最少弹幕数量的轨道
minLen = danmus.length;
minTop = trackTop;
}
if (danmus.length == 0) {
//当前轨道没有弹幕运行,直接插入该轨道
nowTop = trackTop;
break;
} else {
if (danmus.length > 0 && mode == 1) {
//当前轨道有弹幕运行,且弹幕模式是滚动模式时
var arr = danmus.map(function (danmu) {
return danmu.left + danmu.width;
});
var max = Math.max.apply(Math, _toConsumableArray(arr)); //获取当前轨道最右的弹幕
//如果当前轨道还有空位则将弹幕放入当前轨道
if (max < boxWidth - offset - 10) {
//预留10像素间隔
nowTop = trackTop;
break;
}
}
}
}
if (nowTop == -1 && (!config.overlap || force)) {
//没有找到可插入的轨道,但没有开启防重叠或者需要强制显示弹幕,这个弹幕弹幕会无视原来的弹幕开启新的弹幕墙
nowTop = minTop; //将弹幕强制插入最少弹幕数量的轨道
isOverlap = true; //重叠弹幕
}
return {
top: nowTop + top,
//加上上边距top
isOverlap: isOverlap
};
}
//过滤数据
}, {
key: "_filterData",
value: function _filterData(data) {
var _this4 = this;
var config = this.config;
var disableScroll = config.disableScroll;
var disableTop = config.disableTop;
var disableBottom = config.disableBottom;
return YbPlayer.deepClone(data.filter(function (item) {
return (item.mode != 1 || !disableScroll) && (item.mode != 5 || !disableTop) && (item.mode != 4 || !disableBottom) && !_this4.filter.filter(item.text);
}));
}
}, {
key: "_clearAnimationFrame",
value: function _clearAnimationFrame() {
if (this._animation) {
window.cancelAnimationFrame(this._animation);
this._animation = null;
}
}
}], [{
key: "parseBiliXml",
value:
//格式化b站XML文件弹幕
function parseBiliXml(content) {
var pattern = /<d\b[^>]*>(.*?)<\/d\s*>/g;
var danmuku = [];
var match = '';
while ((match = pattern.exec(content)) !== null) {
var attr = match[0].match(/p=\"*([\s\S]*?)\"/)[1];
var attrs = attr.split(',');
danmuku.push({
mode: attrs[1],
time: Number(attrs[0]),
color: YbDanmu.decimalToRgb(Number(attrs[3])),
fontSize: attrs[2],
text: match[1]
});
}
return danmuku;
}
//格式化b站ssa文件弹幕
}, {
key: "parseBiliSsa",
value: function parseBiliSsa(content) {
var lines = content.split('\n');
var events = [];
var currentSection;
lines.forEach(function (line) {
line = line.trim();
if (line.startsWith('[') && line.endsWith(']')) {
currentSection = line.slice(1, -1).toLowerCase();
return;
}
if (currentSection === 'events') {
if (line.toLowerCase().startsWith('format:')) {
// 解析事件格式行
var format = line.slice(7).split(',').map(function (item) {
return item.trim().toLowerCase();
});
// 存储事件格式定义
} else if (line.toLowerCase().startsWith('dialogue:')) {
// 解析对话行
var dialogueValues = line.slice(10).split(',').map(function (item) {
return item.trim();
});
// 注意:文本部分可能包含逗号,所以不能简单分割
var textIndex = 9; // 根据format文本通常是第9个字段从0开始计数
var text = dialogueValues.slice(9).join(','); // 合并文本部分
var dialogueData = {
start: dialogueValues[1],
end: dialogueValues[2],
style: dialogueValues[3],
text: text
};
events.push(dialogueData);
}
}
});
return events.filter(function (e) {
return !e.text.includes('\\a5\\pos');
}).map(function (e) {
var style = e.text.match(/\{*([\s\S]*?)\}/)[1];
var arr = style.split('\\');
return {
mode: 1,
time: timeToSeconds(e.start),
color: arr[2].replace('c&H', '#'),
fontSize: arr[3].replace('fs', ''),
text: e.text.replace(/\{.*?\}/g, '')
};
});
}
//根据文字颜色自动生成反色边框
}, {
key: "getStrokeColor",
value: function getStrokeColor(color) {
var r, g, b;
if (color.startsWith('#')) {
color = color.length == 7 ? color : '#' + color.slice(1, 4) + color.slice(1, 4);
r = parseInt(color.slice(1, 3), 16);
g = parseInt(color.slice(3, 5), 16);
b = parseInt(color.slice(5, 7), 16);
}
if (color.startsWith('rgb')) {
var match = color.match(/rgb\(*([\s\S]*?)\)/);
var colors = match[1].split(',');
r = colors[0];
g = colors[1];
b = colors[2];
}
var $grayLevel = r * 0.299 + g * 0.587 + b * 0.144 / 255;
//判断是否是深色
if ($grayLevel < 0.5) return '#ffffff';else return '#000000';
}
}, {
key: "colorToRgba",
value: function colorToRgba(color, opacity) {
if (color.startsWith('#')) {
color = color.length == 7 ? color : '#' + color.slice(1, 4) + color.slice(1, 4);
var _str = "rgba(";
var _r = parseInt(color.slice(1, 3), 16).toString();
var _g = parseInt(color.slice(3, 5), 16).toString();
var _b = parseInt(color.slice(5, 7), 16).toString();
_str += _r + "," + _g + "," + _b + "," + opacity + ")";
return _str;
}
if (color.startsWith('rgb')) {
var str = "rgba(";
var match = color.match(/rgb\(*([\s\S]*?)\)/);
var colors = match[1].split(',');
var r = colors[0];
var g = colors[1];
var b = colors[2];
str += r + "," + g + "," + b + "," + opacity + ")";
return str;
}
}
//16进制转rgb
}, {
key: "decimalToRgb",
value: function decimalToRgb(decimal) {
var r = decimal >> 16 & 255;
var g = decimal >> 8 & 255;
var b = decimal & 255;
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
}]);
}(); //弹幕过滤
_defineProperty(YbDanmu, "DEFAULT_CONFIG", {
accuracy: 1,
//绘制精度 auto-自动使用屏幕DPI 任意整数-自定义精度 高精度会导致性能问题,谨慎使用
speed: 1,
//弹幕运行速度
playbackRate: 1,
//弹幕倍速
color: '#FFFFFF',
//弹幕默认颜色
fontSize: 18,
//弹幕默认大小
fontScale: 1,
//弹幕规格(多少倍大小)
fontFamily: 'Microsoft Yahei',
//弹幕默认字体
opacity: 1,
//弹幕透明度
top: 0,
//舞台顶部间距
bottom: 0,
//舞台底部间距
lineGap: 5,
//弹幕行间距
overlap: false,
//开启防重叠
timeDiffrence: 0,
//时间差(用于校准弹幕和视频进度的时间差,一般不需要)
disableScroll: false,
//关闭滚动弹幕
disableTop: false,
//关闭顶端弹幕
disableBottom: false,
//关闭底端弹幕
disableFilter: false,
//关闭弹幕过滤
filter: [] //过滤列表
});
var YbDanmuFilter = /*#__PURE__*/function () {
function YbDanmuFilter(list) {
_classCallCheck(this, YbDanmuFilter);
this.rules = list || [];
}
// 添加
return _createClass(YbDanmuFilter, [{
key: "add",
value: function add(rule) {
//判断是否存在同类型的相同规则
var index = this.rules.findIndex(function (r) {
return r.pattern == rule.pattern && r.type == rule.type;
});
if (index > -1) return false; //如果已经存在返回false表示插入失败
this.rules.push(rule);
return true; //添加成功返回true
}
// 删除
}, {
key: "remove",
value: function remove(index) {
this.rules.splice(index, 1);
}
// 过滤弹幕
}, {
key: "filter",
value: function filter(danmu) {
var _iterator = _createForOfIteratorHelper(this.rules),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var rule = _step.value;
if (rule.type === 'string') {
// 字符串匹配
if (danmu.includes(rule.pattern)) {
return true;
}
} else if (rule.type === 'regex') {
// 正则表达式匹配
try {
var regex = new RegExp(rule.pattern);
if (regex.test(danmu)) {
return true;
}
} catch (e) {
console.error('无效的正则表达式:', rule.pattern, e);
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return false;
}
// 获取所有规则
}, {
key: "getRules",
value: function getRules() {
return this.rules;
}
}]);
}(); //兼容new Function为了挂载到window对象上
if (typeof window != 'undefined') {
window.YbDanmu = YbDanmu;
}