ckplayer-plus 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ckplayer.js CHANGED
@@ -141,7 +141,7 @@
141
141
  cdnFallback:true// getPath 失败时是否回退到 jsDelivr(内网可设 false,并配置 pluginPath)
142
142
  };
143
143
  // 打包时替换为真实版本;用于 bundler 下 getPath 失效时的 CDN 回退
144
- var ckplayerPlusDefaultCdn='https://cdn.jsdelivr.net/npm/ckplayer-plus@1.1.3/dist/';
144
+ var ckplayerPlusDefaultCdn='https://cdn.jsdelivr.net/npm/ckplayer-plus@1.1.4/dist/';
145
145
  function ckplayerEmbed(videoObj){
146
146
  /*
147
147
  * rightMenu
@@ -446,7 +446,7 @@
446
446
  }
447
447
  var allowCdn=!vars || vars['cdnFallback']!==false;
448
448
  var cdn=(typeof window!=='undefined' && window.ckplayerPlusCdn) ? window.ckplayerPlusCdn : ckplayerPlusDefaultCdn;
449
- if(!allowCdn || !cdn || cdn.indexOf('1.1.3')>-1){
449
+ if(!allowCdn || !cdn || cdn.indexOf('1.1.4')>-1){
450
450
  // 避免占位版本或显式关闭 CDN 时请求坏地址;交给相对路径或业务 pluginPath
451
451
  return folder+'/'+file;
452
452
  }
@@ -777,8 +777,9 @@
777
777
  /*
778
778
  * hlsSeekTo
779
779
  * 功能:HLS 跳转(去重,避免重复 startLoad 取消进行中的 .ts 请求)
780
+ * 一律按分片对齐点 startLoad;缓冲已覆盖但 currentTime 未到位时只 finishResumeSeek
780
781
  * @force 强制重新加载
781
- * @returns true=已由 HLS 处理(含 no-op),false=非 HLS 或未处理
782
+ * @returns true=已由 HLS 处理(含 no-op / 已交 finishResumeSeek),false=非 HLS 或未处理
782
783
  */
783
784
  hlsSeekTo=function(target,force){
784
785
  if(!hls || typeof hls.startLoad!=='function' || !video){
@@ -788,28 +789,30 @@
788
789
  target=0;
789
790
  }
790
791
  var curTime=video.currentTime || 0;
791
- if(!force){
792
- // startPosition / 上次 startLoad 已针对同一续播点,且缓冲已覆盖 → 不再重启
793
- if(hlsResumeTarget>=0 && Math.abs(hlsResumeTarget-target)<1.5){
794
- if(timeInBuffered(target) && Math.abs(curTime-target)<2.5){
795
- return true;
796
- }
792
+ hlsResumeTarget=target;
793
+ // 缓冲已覆盖:只定位,禁止再 startLoad(否则会 cancel 刚下好的中段分片)
794
+ if(!force && timeInBuffered(target)){
795
+ if(Math.abs(curTime-target)<1.5){
796
+ return true;
797
797
  }
798
- // 已在目标附近且可播 → 跳过
799
- if(timeInBuffered(target) && Math.abs(curTime-target)<1.5){
800
- hlsResumeTarget=target;
798
+ if(hlsCanSafelySeekTo(target)){
799
+ finishResumeSeek(target);
801
800
  return true;
802
801
  }
803
- // 短时间内重复 seek 同一点 跳过(防止 onReady 再 seek 取消分片)
804
- if(hlsLoadAt>=0 && Math.abs(hlsLoadAt-target)<1.5 && (Date.now()-hlsLoadTs)<4000){
802
+ // 目标已在缓冲但缺少前片连续区继续按对齐点预热,勿 noop
803
+ }
804
+ var loadAt=hlsPriorLoadTime(target);
805
+ if(!force){
806
+ // 短时间内已对同一对齐点发起加载 → 跳过(防止 onReady 再 seek 取消分片)
807
+ if(hlsLoadAt>=0 && Math.abs(hlsLoadAt-loadAt)<1.5 && (Date.now()-hlsLoadTs)<4000){
805
808
  return true;
806
809
  }
807
810
  }
808
- hlsLoadAt=target;
811
+ hlsLoadAt=loadAt;
809
812
  hlsLoadTs=Date.now();
810
- hlsResumeTarget=target;
813
+ hlsResumeWarmup=true;
811
814
  try{
812
- hls.startLoad(target);
815
+ hls.startLoad(loadAt);
813
816
  }catch(event){
814
817
  return false;
815
818
  }
@@ -1000,8 +1003,8 @@
1000
1003
  if(!resumeAt){
1001
1004
  resumeAt=parseResumeSeekFromVars();
1002
1005
  }
1003
- // HLS 续播:不要用精确秒数做 startPosition(易在分片中部起播导致解码失败/永久 loading)。
1004
- // 对齐目标分片起点加载,等分片从起点缓冲到目标后再一次 currentTime,并强制 play
1006
+ // HLS 续播:autoStartLoad=false,避免默认从 0 拉片后再 startLoad 导致 .ts canceled。
1007
+ // 清单解析后只 startLoad 一次(对齐目标前一片),缓冲覆盖后再 currentTime。
1005
1008
  if(resumeAt && resumeAt>0 && (isUndefined(vars['live']) || !vars['live'])){
1006
1009
  maxSeeTime=Math.max(maxSeeTime,resumeAt);
1007
1010
  if(firstSeekTime<0){
@@ -1010,6 +1013,7 @@
1010
1013
  seekTime=resumeAt;
1011
1014
  hlsResumeTarget=resumeAt;
1012
1015
  hlsResumeWarmup=true;
1016
+ hlsConf.autoStartLoad=false;
1013
1017
  }
1014
1018
  hls = new Hls(hlsConf);
1015
1019
  hls.loadSource(url);
@@ -1017,10 +1021,13 @@
1017
1021
  hls.on(Hls.Events.MANIFEST_PARSED, function(){
1018
1022
  if(hlsResumeWarmup && seekTime>0){
1019
1023
  var loadAt=hlsPriorLoadTime(seekTime);
1024
+ hlsLoadAt=loadAt;
1025
+ hlsLoadTs=Date.now();
1026
+ hlsStartPositionUsed=true;
1020
1027
  try{
1021
1028
  hls.startLoad(loadAt);
1022
1029
  }catch(event){}
1023
- // 超时兜底:仍未定位则对齐分片起点起播,避免一直转圈
1030
+ // 超时兜底:仍未定位则落到可解码的对齐点,避免一直转圈
1024
1031
  setTimeout(function(){
1025
1032
  if(!hlsResumeWarmup || !seekTime){return;}
1026
1033
  var target=seekTime;
@@ -1028,9 +1035,12 @@
1028
1035
  finishResumeSeek(target);
1029
1036
  return;
1030
1037
  }
1031
- var snap=hlsPriorLoadTime(target);
1032
- hlsResumeWarmup=false;
1033
- finishResumeSeek(snap);
1038
+ var snap=hlsFragStartTime(target);
1039
+ if(timeInBuffered(snap) || hlsCanSafelySeekTo(snap)){
1040
+ finishResumeSeek(snap);
1041
+ return;
1042
+ }
1043
+ finishResumeSeek(Math.max(0,loadAt));
1034
1044
  },5000);
1035
1045
  return;
1036
1046
  }
@@ -1851,11 +1861,11 @@
1851
1861
  return false;
1852
1862
  },
1853
1863
  /*
1854
- * hlsFragAround
1855
- * 功能:查找覆盖指定时间的 HLS 分片(用于对齐关键帧起点)
1864
+ * hlsGetFragments
1865
+ * 功能:取当前/首选清晰度的分片列表
1856
1866
  */
1857
- hlsFragAround=function(t){
1858
- if(!hls || isNaN(t) || t<0){
1867
+ hlsGetFragments=function(){
1868
+ if(!hls){
1859
1869
  return null;
1860
1870
  }
1861
1871
  try{
@@ -1874,6 +1884,23 @@
1874
1884
  if(!frags || !frags.length){
1875
1885
  return null;
1876
1886
  }
1887
+ return frags;
1888
+ }catch(event){}
1889
+ return null;
1890
+ },
1891
+ /*
1892
+ * hlsFragAround
1893
+ * 功能:查找覆盖指定时间的 HLS 分片(用于对齐关键帧起点)
1894
+ */
1895
+ hlsFragAround=function(t){
1896
+ if(!hls || isNaN(t) || t<0){
1897
+ return null;
1898
+ }
1899
+ try{
1900
+ var frags=hlsGetFragments();
1901
+ if(!frags){
1902
+ return null;
1903
+ }
1877
1904
  for(var i=0;i<frags.length;i++){
1878
1905
  var f=frags[i];
1879
1906
  if(!f){continue;}
@@ -1888,23 +1915,70 @@
1888
1915
  }catch(event){}
1889
1916
  return null;
1890
1917
  },
1918
+ /*
1919
+ * hlsFragIndexAround
1920
+ * 功能:返回覆盖指定时间的分片下标
1921
+ */
1922
+ hlsFragIndexAround=function(t){
1923
+ var frags=hlsGetFragments();
1924
+ if(!frags || isNaN(t) || t<0){
1925
+ return -1;
1926
+ }
1927
+ for(var i=0;i<frags.length;i++){
1928
+ var f=frags[i];
1929
+ if(!f){continue;}
1930
+ var start=f.start||0;
1931
+ var end=start+(f.duration||0);
1932
+ if(t>=start-0.05 && t<end+0.05){
1933
+ return i;
1934
+ }
1935
+ }
1936
+ return frags.length-1;
1937
+ },
1938
+ /*
1939
+ * hlsFragStartTime
1940
+ * 功能:目标所在分片的起点(用于超时兜底定位)
1941
+ */
1942
+ hlsFragStartTime=function(t){
1943
+ if(isNaN(t) || t<=0){
1944
+ return 0;
1945
+ }
1946
+ var frag=hlsFragAround(t);
1947
+ if(frag && !isUndefined(frag.start)){
1948
+ return Math.max(0,frag.start);
1949
+ }
1950
+ return Math.max(0,t);
1951
+ },
1891
1952
  /*
1892
1953
  * hlsPriorLoadTime
1893
- * 功能:续播加载起点——优先对齐目标分片起点(该流分片开头通常有 IDR
1954
+ * 功能:续播加载起点——回退到目标前一片(教育流片头常无 IDR,需前一片建解码管线)
1894
1955
  */
1895
1956
  hlsPriorLoadTime=function(t){
1896
1957
  if(isNaN(t) || t<=0){
1897
1958
  return 0;
1898
1959
  }
1960
+ var frags=hlsGetFragments();
1961
+ if(frags && frags.length){
1962
+ var idx=hlsFragIndexAround(t);
1963
+ if(idx<0){
1964
+ idx=frags.length-1;
1965
+ }
1966
+ var loadIdx=Math.max(0,idx-1);
1967
+ var loadFrag=frags[loadIdx];
1968
+ if(loadFrag && !isUndefined(loadFrag.start)){
1969
+ return Math.max(0,loadFrag.start);
1970
+ }
1971
+ }
1899
1972
  var frag=hlsFragAround(t);
1900
1973
  if(frag && !isUndefined(frag.start)){
1901
- return Math.max(0,frag.start);
1974
+ // 清单未就绪时至少对齐目标片起点,再额外回退约一片时长
1975
+ return Math.max(0,frag.start-12);
1902
1976
  }
1903
1977
  return Math.max(0,t-12);
1904
1978
  },
1905
1979
  /*
1906
1980
  * hlsCanSafelySeekTo
1907
- * 功能:目标分片已从分片起点连续缓冲到目标点,才允许 currentTime
1981
+ * 功能:从预热加载起点(目标前一片)到目标点已连续缓冲,才允许 currentTime
1908
1982
  * 避免分片未完整进入 MSE 时中途 seek 触发 PIPELINE_ERROR_DECODE / 永久 loading
1909
1983
  */
1910
1984
  hlsCanSafelySeekTo=function(t){
@@ -1914,14 +1988,14 @@
1914
1988
  if(!timeInBuffered(t)){
1915
1989
  return false;
1916
1990
  }
1917
- var fragStart=hlsPriorLoadTime(t);
1918
- // 同一连续区间需覆盖分片起点→目标
1991
+ var loadStart=hlsPriorLoadTime(t);
1992
+ // 同一连续区间需覆盖预热起点→目标
1919
1993
  try{
1920
1994
  var buf=video.buffered;
1921
1995
  for(var i=0;i<buf.length;i++){
1922
1996
  var start=buf.start(i);
1923
1997
  var end=buf.end(i);
1924
- if(fragStart>=start-0.35 && t<=end+0.15){
1998
+ if(loadStart>=start-0.35 && t<=end+0.15){
1925
1999
  return true;
1926
2000
  }
1927
2001
  }
@@ -2002,6 +2076,7 @@
2002
2076
  * applyPendingSeek
2003
2077
  * 功能:在媒体就绪且目标时间可解码后再应用挂起的 seekTime
2004
2078
  * 避免断点续播过早 seek 触发 PIPELINE_ERROR_DECODE(非关键帧)
2079
+ * seekTime 仅在 finishResumeSeek / applySeekToMedia 成功后清零
2005
2080
  */
2006
2081
  applyPendingSeek=function(force){
2007
2082
  if(!seekTime || !video || seekApplyLock){
@@ -2026,21 +2101,30 @@
2026
2101
  firstSeekTime=t;
2027
2102
  }
2028
2103
  }
2029
- // HLS 首分片尚未完成预热时不能直接 startLoad(target)
2030
- if(hlsResumeWarmup){
2104
+ // HLS:缓冲已可安全定位 只 finish,禁止再 startLoad / 勿提前清 seekTime
2105
+ if(hls && typeof hls.startLoad==='function'){
2031
2106
  if(hlsCanSafelySeekTo(t)){
2032
2107
  finishResumeSeek(t);
2108
+ return;
2033
2109
  }
2034
- return;
2035
- }
2036
- // HLS:用 hls.startLoad 从目标分片起点加载(去重,避免取消进行中的 .ts)
2037
- if(hls && typeof hls.startLoad==='function'){
2038
- if(!hlsCanSafelySeekTo(t) && t>1){
2110
+ // 预热中或需加载:只按对齐点 startLoad(去重),保留 seekTime 等 FRAG_BUFFERED
2111
+ if(t>1){
2039
2112
  hlsResumeWarmup=true;
2040
2113
  hlsResumeTarget=t;
2041
- try{
2042
- hls.startLoad(hlsPriorLoadTime(t));
2043
- }catch(event){}
2114
+ var loadAt=hlsPriorLoadTime(t);
2115
+ var shouldLoad=!!force;
2116
+ if(!shouldLoad){
2117
+ if(!(hlsLoadAt>=0 && Math.abs(hlsLoadAt-loadAt)<1.5 && (Date.now()-hlsLoadTs)<4000)){
2118
+ shouldLoad=true;
2119
+ }
2120
+ }
2121
+ if(shouldLoad){
2122
+ hlsLoadAt=loadAt;
2123
+ hlsLoadTs=Date.now();
2124
+ try{
2125
+ hls.startLoad(loadAt);
2126
+ }catch(event){}
2127
+ }
2044
2128
  seekRetryCount++;
2045
2129
  if(seekRetryCount<=50){
2046
2130
  if(seekRetryTimer){
@@ -2052,11 +2136,6 @@
2052
2136
  }
2053
2137
  return;
2054
2138
  }
2055
- if(hlsSeekTo(t, !!force)){
2056
- clearSeekRetry();
2057
- seekTime=0;
2058
- return;
2059
- }
2060
2139
  }
2061
2140
  // 对普通 MP4,metadata 后设置 currentTime 会由浏览器自动请求目标 Range。
2062
2141
  // 等待目标已缓冲会形成循环等待:目标分片只有 seek 后才会下载。
@@ -3449,20 +3528,20 @@
3449
3528
  applyPendingSeek(false);
3450
3529
  return player;
3451
3530
  }
3452
- // HLS:无前序关键帧缓冲时禁止直接 startLoad(target)
3453
- if(hls && target>1 && !hlsCanSafelySeekTo(target)){
3531
+ // HLS:缓冲已覆盖则只定位;否则按对齐点预热,seekTime 保留至 finishResumeSeek
3532
+ if(hls){
3454
3533
  seekTime=target;
3455
- hlsResumeWarmup=true;
3456
3534
  hlsResumeTarget=target;
3457
- try{
3458
- hls.startLoad(hlsPriorLoadTime(target));
3459
- }catch(event){}
3460
- applyPendingSeek(false);
3461
- return player;
3462
- }
3463
- if(hlsSeekTo(target, false)){
3464
- seekTime=0;
3465
- return player;
3535
+ if(target>1 && hlsCanSafelySeekTo(target)){
3536
+ finishResumeSeek(target);
3537
+ return player;
3538
+ }
3539
+ if(target>1){
3540
+ hlsResumeWarmup=true;
3541
+ hlsSeekTo(target, false);
3542
+ applyPendingSeek(false);
3543
+ return player;
3544
+ }
3466
3545
  }
3467
3546
  try{
3468
3547
  video.currentTime=target;
@@ -7282,7 +7361,7 @@
7282
7361
  if(!isRetry && (!vars || vars['cdnFallback']!==false)){
7283
7362
  var cdn=(typeof window!=='undefined' && window.ckplayerPlusCdn) ? window.ckplayerPlusCdn : ckplayerPlusDefaultCdn;
7284
7363
  var m=String(file).match(/\/(hls\.js|flv\.js|mpegts\.js|language)\/([^/?#]+)(?:[?#].*)?$/i);
7285
- if(cdn && cdn.indexOf('1.1.3')===-1 && m){
7364
+ if(cdn && cdn.indexOf('1.1.4')===-1 && m){
7286
7365
  if(cdn.slice(-1)!=='/'){
7287
7366
  cdn+='/';
7288
7367
  }