@@ -65,13 +65,18 @@ var YbPlayer = /*#__PURE__*/function () {
this . loop = loop ; //是否循环播放
this . muted = muted ; //是否静音
this . playbackRate = playbackRate || 1 ; //默认播放倍速
console . log ( '倍速列表' + JSON . stringify ( playbackRates ) )
this . playbackRates = playbackRates && playbackRates . length > 0 ? playbackRates : [ {
text : '0.5倍速' ,
value : 0.5
} , {
text : '0.75倍速' ,
value : 0.75
} , {
text : '正常倍速' ,
value : 1
} , {
text : '1.25倍速' ,
value : 1.25
} , {
text : '1.5倍速' ,
value : 1.5
@@ -120,6 +125,9 @@ var YbPlayer = /*#__PURE__*/function () {
this . _toastTimer = null ; //消息隐藏定时器
this . _danmuTimer = null ; //弹幕定时器
this . _seizingTimer = null ; //卡死定时器(播放一些直播源的时候,可能会出现卡死无反应的情况,需要做出处理)
this . _rateTimer = null ; //倍速显示定时器
this . _errorRetryCount = 0 ; //错误重试次数
this . _maxErrorRetry = 0 ; //最大重试次数
this . _event = { } ;
}
//开启全屏按钮
@@ -157,6 +165,7 @@ var YbPlayer = /*#__PURE__*/function () {
this . _clearDanmuTimer ( ) ;
this . _clearToastTimer ( ) ;
this . _clearControlsTimer ( ) ;
this . _clearRateTimer ( ) ;
this . _removeBackbuttonListener ( ) ;
this . _event = { } ; //卸载所有监听事件
if ( this . container ) {
@@ -226,8 +235,8 @@ var YbPlayer = /*#__PURE__*/function () {
_this2 . emit ( 'durationchange' , _this2 . getDuration ( ) ) ;
} ;
this . video . onloadeddata = function ( ) {
//非直播时初始化播放时长
if ( _this2 . initialTime && ! _this2 . isLive ) _this2 . seek ( _this2 . initialTime ) ;
//非直播时初始化播放时长(错误恢复时不执行)
if ( _this2 . initialTime && ! _this2 . isLive && ! _this2 . _isErrorRecovering ) _this2 . seek ( _this2 . initialTime ) ;
_this2 . emit ( 'loadeddata' , {
duration : _this2 . getDuration ( ) ,
videoWidth : _this2 . video . videoWidth ,
@@ -255,12 +264,18 @@ var YbPlayer = /*#__PURE__*/function () {
if ( _this2 . cm ) _this2 . cm . setConfig ( 'playbackRate' , playbackRate ) ;
_this2 . emit ( 'ratechange' , playbackRate ) ;
_this2 . setInnerHTML ( 'yb-player-header-rate' , '倍速x' + playbackRate ) ;
_this2 . _clearRateTimer ( ) ;
var rateEl = _this2 . container . getElementsByClassName ( 'yb-player-rate' ) [ 0 ] || document . createElement ( 'DIV' ) ;
if ( ! [ 1 , 1.0 ] . includes ( playbackRate ) ) {
rateEl . setAttribute ( 'class' , 'yb-player-rate' ) ;
rateEl . innerHTML = "\n\t\t\t\t\t<div class=\"yb-player-rate-icon\">\n\t\t\t\t\t\t<i></i><i></i><i></i>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"yb-player-rate-span\">" . concat ( playbackRate + '倍速播放中' , "</span>\n\t\t\t\t" ) ;
var wrapperEl = _this2 . container . getElementsByClassName ( 'yb-player-wrapper' ) [ 0 ] ;
if ( wrapperEl ) wrapperEl . appendChild ( rateEl ) ;
_this2 . _rateTimer = window . setTimeout ( function ( ) {
if ( rateEl && rateEl . parentNode ) {
rateEl . parentNode . removeChild ( rateEl ) ;
}
} , 2000 ) ;
} else {
if ( rateEl ) rateEl . remove ( ) ;
}
@@ -353,7 +368,6 @@ var YbPlayer = /*#__PURE__*/function () {
} ;
this . video . onerror = function ( e ) {
if ( e && e . target . error ) {
// 网络问题或其他不可恢复的错误
var code = e . target . error . code ;
var errorMsg = '' ;
switch ( code ) {
@@ -370,10 +384,26 @@ var YbPlayer = /*#__PURE__*/function () {
errorMsg = '视频源不支持或地址无效' ;
break ;
}
console . log ( '[video.onerror] 检测到视频错误,错误码:' + code + ', 错误信息:' + errorMsg ) ;
// 错误码 3 尝试跳过问题区间后继续播放
if ( code === 3 ) {
_this2 . _skipErrorAndRetry ( errorMsg ) ;
} else {
// 其他错误直接提示错误信息
_this2 . showError ( errorMsg ) ;
_this2 . unloadVideo ( ) ;
}
// emit 错误事件,传递详细的错误信息
_this2 . emit ( 'error' , {
code : code ,
message : errorMsg ,
error : e
} ) ;
} else {
_this2 . emit ( 'error' , e ) ;
}
} ;
//视频长按菜单取消
this . video . oncontextmenu = function ( e ) {
@@ -410,6 +440,7 @@ var YbPlayer = /*#__PURE__*/function () {
key : "unloadVideo" ,
value : function unloadVideo ( ) {
this . _clearSeizingTimer ( ) ;
this . _errorRetryCount = 0 ; // 重置错误计数
this . unloadCustom ( ) ;
this . unloadDecoder ( ) ;
this . unloadPano ( ) ;
@@ -1430,7 +1461,7 @@ var YbPlayer = /*#__PURE__*/function () {
if ( [ 'timeDiffrence' , 'disableScroll' , 'disableTop' , 'disableBottom' , 'fontScale' ] . includes ( key ) ) _this . cm . reset ( ) ;
}
_this . emit ( 'danmuconfigchange' , config ) ; //派发弹幕配置更改事件,以便开发者外部记录
} , 5 00) ;
} , 20 00) ;
}
this . showPopup ( '弹幕设置' , div ) ;
}
@@ -2451,7 +2482,14 @@ var YbPlayer = /*#__PURE__*/function () {
value : function hideLoading ( ) {
var div = this . container . getElementsByClassName ( 'yb-player-loading' ) [ 0 ] ;
if ( div ) div . remove ( ) ;
if ( this . video . paused ) this . showCenterPlay( ) ; else this. hideCenter( ) ;
// if (this.video.paused) this. showCenterPlay(); else this. hideCenter();
if ( this . _isErrorRecovering ) {
this . hideCenter ( ) ;
} else if ( this . video . paused ) {
this . showCenterPlay ( ) ;
} else {
this . hideCenter ( ) ;
}
}
//展示中间播放按钮
} , {
@@ -2561,6 +2599,152 @@ var YbPlayer = /*#__PURE__*/function () {
value : function seek ( time ) {
if ( this . video ) this . video . currentTime = time ;
}
/**
* 跳过错误区间并重试播放
* @param {String} errorMsg 错误信息
*/
} , {
key : "_skipErrorAndRetry" ,
value : function _skipErrorAndRetry ( errorMsg ) {
var _this = this ;
// 检查 video 对象是否存在
if ( ! this . video ) {
console . log ( '[错误恢复] video 对象不存在,无法恢复' ) ;
this . showError ( errorMsg ) ;
this . unloadVideo ( ) ;
return ;
}
// 超过最大重试次数,显示错误并卸载视频
if ( this . _errorRetryCount >= this . _maxErrorRetry ) {
this . showError ( errorMsg ) ;
this . unloadVideo ( ) ;
return ;
}
this . _errorRetryCount ++ ;
// 第 1 次错误静默处理,显示 loading
if ( this . _errorRetryCount === 1 ) {
this . showLoading ( ) ;
}
// 获取当前播放时间,向后跳过 1 秒(跳过损坏的 GOP 区间)
var currentTime = this . video . currentTime || 0 ;
// 确保 currentTime 是有效数字
if ( isNaN ( currentTime ) || currentTime < 0 ) {
currentTime = 0 ;
}
var duration = this . getDuration ( ) || 0 ;
var skipTime = Math . min ( currentTime + 1 , duration ) ;
console . log ( '[错误恢复] 开始处理,当前时间:' + currentTime + 's, 跳转到:' + skipTime + 's' ) ;
// 关键:保存当前 src, 然后重新加载视频来恢复状态
// var currentSrc = this.video.currentSrc || this.video.src;
console . log ( '[错误恢复] 重新加载视频...' ) ;
// 保存当前倍速设置
var currentPlaybackRate = this . video . playbackRate || 1 ;
console . log ( '[错误恢复] 保存倍速:' + currentPlaybackRate ) ;
// 设置标志,告诉 loadeddata 不要执行 seek
this . _isErrorRecovering = true ;
// 重新设置 src 并加载
// this.video.src = currentSrc;
this . video . load ( ) ;
// 清除之前的定时器(如果有)
if ( this . _errorRecoveryTimer ) {
clearTimeout ( this . _errorRecoveryTimer ) ;
}
// 等待元数据加载完成
var onLoadedMetadata = function ( ) {
// 检查 video 对象是否仍然存在
if ( ! _this . video ) {
console . log ( '[错误恢复] loadedmetadata 触发,但 video 对象已不存在' ) ;
return ;
}
console . log ( '[错误恢复] loadedmetadata 触发,设置 currentTime = ' + skipTime ) ;
_this . video . removeEventListener ( 'loadedmetadata' , onLoadedMetadata ) ;
// 清除超时定时器
if ( _this . _errorRecoveryTimer ) {
clearTimeout ( _this . _errorRecoveryTimer ) ;
}
// 恢复倍速设置
_this . video . playbackRate = currentPlaybackRate ;
console . log ( '[错误恢复] 恢复倍速:' + currentPlaybackRate ) ;
// 设置跳转位置
_this . video . currentTime = skipTime ;
// 等待 seek 完成后立即播放
var onSeeked = function ( ) {
// 检查 video 对象是否仍然存在
if ( ! _this2 . video ) {
console . log ( '[错误恢复] seeked 触发,但 video 对象已不存在' ) ;
return ;
}
console . log ( '[错误恢复] seeked 触发,实际位置:' + _this2 . video . currentTime ) ;
_this2 . video . removeEventListener ( 'seeked' , onSeeked ) ;
_this2 . tryPlayAfterSeek ( errorMsg ) ;
} ;
_this . video . addEventListener ( 'seeked' , onSeeked ) ;
} ;
this . video . addEventListener ( 'loadedmetadata' , onLoadedMetadata ) ;
// loadedmetadata 超时处理
this . _errorRecoveryTimer = setTimeout ( function ( ) {
console . log ( '[错误恢复] loadedmetadata 超时,直接尝试播放' ) ;
if ( _this . video ) {
_this . video . removeEventListener ( 'loadedmetadata' , onLoadedMetadata ) ;
}
_this . tryPlayAfterSeek ( errorMsg ) ;
} , 5000 ) ;
}
// 尝试播放
} , {
key : "tryPlayAfterSeek" ,
value : function tryPlayAfterSeek ( errorMsg ) {
var _this2 = this ;
console . log ( '[错误恢复] 准备播放, 当前状态: paused=' + this . video . paused + ', readyState=' + this . video . readyState + ', currentTime=' + this . video . currentTime ) ;
// 直接调用 play(), Promise 会处理缓冲
var playPromise = this . video . play ( ) ;
console . log ( '[错误恢复] play() 已调用' ) ;
if ( playPromise && typeof playPromise . then === 'function' ) {
playPromise . then ( function ( ) {
console . log ( '[错误恢复] 播放成功!' ) ;
_this2 . _errorRetryCount = 0 ;
_this2 . _isErrorRecovering = false ; // 清除错误恢复标志
// 清除所有定时器
if ( _this2 . _errorRecoveryTimer ) {
clearTimeout ( _this2 . _errorRecoveryTimer ) ;
_this2 . _errorRecoveryTimer = null ;
}
_this2 . hideLoading ( ) ;
} ) . catch ( function ( err ) {
console . log ( '[错误恢复] 播放失败:' , err ) ;
_this2 . _skipErrorAndRetry ( errorMsg ) ;
} ) ;
} else {
_this2 . _errorRetryCount = 0 ;
_this2 . _isErrorRecovering = false ;
_this2 . hideLoading ( ) ;
}
}
//播放上一个视频
} , {
key : "prev" ,
@@ -2962,6 +3146,14 @@ var YbPlayer = /*#__PURE__*/function () {
this . _seizingTimer = null ;
}
}
} , {
key : "_clearRateTimer" ,
value : function _clearRateTimer ( ) {
if ( this . _rateTimer ) {
window . clearTimeout ( this . _rateTimer ) ;
this . _rateTimer = null ;
}
}
} , {
key : "_removeBackbuttonListener" ,
value : function _removeBackbuttonListener ( ) {