@volcengine/veplayer 1.15.1 → 1.15.2-rc.1

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.

Potentially problematic release.


This version of @volcengine/veplayer might be problematic. Click here for more details.

Files changed (245) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.changeset/curvy-yaks-smoke.md +5 -0
  3. package/.changeset/neat-eyes-search.md +5 -0
  4. package/.codebase/pipelines/create-api-doc.yaml +16 -0
  5. package/.eslintignore +5 -0
  6. package/.eslintrc.json +53 -0
  7. package/.stylelintrc.js +51 -0
  8. package/CHANGELOG.md +5665 -0
  9. package/DEV_README.md +39 -0
  10. package/LICENSE +20 -0
  11. package/README_EN.md +46 -0
  12. package/build.sh +44 -0
  13. package/docg.config.js +65 -0
  14. package/env/byteplus.js +30 -0
  15. package/env/volcengine.js +50 -0
  16. package/fixtures/favicon.ico +0 -0
  17. package/fixtures/index.base.js +59 -0
  18. package/fixtures/index.html +41 -0
  19. package/fixtures/index.js +185 -0
  20. package/libd.config.js +147 -0
  21. package/localhost+2-key.pem +28 -0
  22. package/localhost+2.pem +26 -0
  23. package/lux.config.mjs +37 -0
  24. package/package.json +123 -4
  25. package/sdkhub.config.json +10 -0
  26. package/src/@types/global.d.ts +35 -0
  27. package/src/assets/common/error.svg +3 -0
  28. package/src/assets/common/errorImg.png +0 -0
  29. package/src/assets/common/errorImg.svg +12 -0
  30. package/src/assets/icons/mobile/definition.svg +3 -0
  31. package/src/assets/icons/mobile/line.svg +3 -0
  32. package/src/assets/icons/mobile/mobileDanmu.svg +1 -0
  33. package/src/assets/icons/mobile/mobileDanmuAcitive.svg +1 -0
  34. package/src/assets/icons/mobile/mobileDanmuSetting.svg +1 -0
  35. package/src/assets/icons/mobile/mobileExitFullscreen.svg +1 -0
  36. package/src/assets/icons/mobile/mobileFullscreen.svg +1 -0
  37. package/src/assets/icons/mobile/mobilePause.svg +4 -0
  38. package/src/assets/icons/mobile/mobilePlay.svg +4 -0
  39. package/src/assets/icons/mobile/mobilePlaynext.svg +1 -0
  40. package/src/assets/icons/mobile/mobileRefresh.svg +1 -0
  41. package/src/assets/icons/mobile/more.svg +3 -0
  42. package/src/assets/icons/mobile/muted.svg +22 -0
  43. package/src/assets/icons/mobile/playbackrate.svg +3 -0
  44. package/src/assets/icons/pc/danmu.svg +1 -0
  45. package/src/assets/icons/pc/danmuActive.svg +1 -0
  46. package/src/assets/icons/pc/danmuSettings.svg +1 -0
  47. package/src/assets/icons/pc/download.svg +14 -0
  48. package/src/assets/icons/pc/exitFullscreen.svg +1 -0
  49. package/src/assets/icons/pc/exitMirror.svg +10 -0
  50. package/src/assets/icons/pc/extend.svg +1 -0
  51. package/src/assets/icons/pc/fullscreen.svg +1 -0
  52. package/src/assets/icons/pc/getMirror.svg +10 -0
  53. package/src/assets/icons/pc/list.svg +20 -0
  54. package/src/assets/icons/pc/noPoster.svg +119 -0
  55. package/src/assets/icons/pc/pause.svg +1 -0
  56. package/src/assets/icons/pc/pip.svg +1 -0
  57. package/src/assets/icons/pc/pipExit.svg +1 -0
  58. package/src/assets/icons/pc/play-next-btn.svg +4 -0
  59. package/src/assets/icons/pc/play.svg +1 -0
  60. package/src/assets/icons/pc/playNext.svg +1 -0
  61. package/src/assets/icons/pc/playerLoading.svg +1 -0
  62. package/src/assets/icons/pc/refresh.svg +1 -0
  63. package/src/assets/icons/pc/replay.svg +1 -0
  64. package/src/assets/icons/pc/reset.svg +6 -0
  65. package/src/assets/icons/pc/startPlay.svg +1 -0
  66. package/src/assets/icons/pc/subtitleclose.svg +5 -0
  67. package/src/assets/icons/pc/subtitleopen.svg +3 -0
  68. package/src/assets/icons/pc/theaterEnter.svg +1 -0
  69. package/src/assets/icons/pc/theaterExit.svg +1 -0
  70. package/src/assets/icons/pc/volumeLarge.svg +1 -0
  71. package/src/assets/icons/pc/volumeMuted.svg +1 -0
  72. package/src/assets/icons/pc/volumeSmall.svg +1 -0
  73. package/src/config/defaultPreset.ts +110 -0
  74. package/src/config/playerOptionMobile.ts +166 -0
  75. package/src/config/playerOptionPc.ts +147 -0
  76. package/src/config/playerPreset.ts +242 -0
  77. package/src/constants/api.ts +13 -0
  78. package/src/constants/event.ts +577 -0
  79. package/src/constants/player.ts +84 -0
  80. package/src/constants/plugin.ts +19 -0
  81. package/src/constants/umdMap.ts +137 -0
  82. package/src/constants/umdPlugins.json +68 -0
  83. package/src/core/index.ts +7 -0
  84. package/src/core/player.ts +2713 -0
  85. package/src/core/playerData.ts +812 -0
  86. package/src/env.d.ts +47 -0
  87. package/src/index.ts +24 -0
  88. package/src/index.umd.ts +54 -0
  89. package/src/interface/adaptRange.d.ts +33 -0
  90. package/src/interface/api.ts +132 -0
  91. package/src/interface/autoBitrate.d.ts +41 -0
  92. package/src/interface/index.ts +1685 -0
  93. package/src/interface/rtm.ts +56 -0
  94. package/src/interface/sdkErrorPlugin.ts +145 -0
  95. package/src/interface/subtitle.ts +381 -0
  96. package/src/interface/video.ts +107 -0
  97. package/src/interface/xgplayer.ts +748 -0
  98. package/src/lang/constants.ts +69 -0
  99. package/src/lang/en.ts +98 -0
  100. package/src/lang/index.ts +33 -0
  101. package/src/lang/jp.ts +100 -0
  102. package/src/lang/zh-hk.ts +80 -0
  103. package/src/lang/zh.ts +79 -0
  104. package/src/license/index.ts +315 -0
  105. package/src/license/ttlicense2.js +15 -0
  106. package/src/license/ttlicense2.wasm +0 -0
  107. package/src/music/icons/back.svg +3 -0
  108. package/src/music/icons/forward.svg +3 -0
  109. package/src/music/icons/loop.svg +10 -0
  110. package/src/music/icons/order.svg +10 -0
  111. package/src/music/icons/pause-circle.svg +23 -0
  112. package/src/music/icons/play-circle.svg +22 -0
  113. package/src/music/icons/random.svg +10 -0
  114. package/src/music/icons/sloop.svg +10 -0
  115. package/src/music/index.ts +5 -0
  116. package/src/music/music.ts +550 -0
  117. package/src/music/plugins/index.less +185 -0
  118. package/src/music/plugins/index.ts +6 -0
  119. package/src/music/plugins/musicBackward.ts +82 -0
  120. package/src/music/plugins/musicCover.ts +45 -0
  121. package/src/music/plugins/musicForward.ts +82 -0
  122. package/src/music/plugins/musicMeta.ts +32 -0
  123. package/src/music/plugins/musicMode.ts +152 -0
  124. package/src/music/plugins/musicNext.ts +93 -0
  125. package/src/music/plugins/musicPrev.ts +94 -0
  126. package/src/music/preset.ts +69 -0
  127. package/src/music/xhr.ts +37 -0
  128. package/src/plugins/common/extendPluginFactory.ts +132 -0
  129. package/src/plugins/common/mobilePlayerPanel.ts +253 -0
  130. package/src/plugins/external/LiveInfoPanel.ts +340 -0
  131. package/src/plugins/external/ad/adsPlugin.ts +1 -0
  132. package/src/plugins/external/aiSubtitleIconPlugin.ts +270 -0
  133. package/src/plugins/external/aiSubtitlePlugin.ts +452 -0
  134. package/src/plugins/external/definitionDemotePlugin.ts +591 -0
  135. package/src/plugins/external/memoryPlay.ts +247 -0
  136. package/src/plugins/external/mirrorPlugin.ts +141 -0
  137. package/src/plugins/external/playList/OptionList.ts +204 -0
  138. package/src/plugins/external/playList/index.ts +743 -0
  139. package/src/plugins/external/subtitle/index.ts +672 -0
  140. package/src/plugins/external/subtitle/nativeSubTitle.ts +115 -0
  141. package/src/plugins/external/timeShiftPlugin.ts +484 -0
  142. package/src/plugins/external/watermark/dynamicWatermark.less +13 -0
  143. package/src/plugins/external/watermark/dynamicWatermark.ts +449 -0
  144. package/src/plugins/external/watermark/dynamicWatermarkPlugin.ts +185 -0
  145. package/src/plugins/inner/common/autoplayPlugin.ts +435 -0
  146. package/src/plugins/inner/common/danmu/container.ts +120 -0
  147. package/src/plugins/inner/common/danmu/index.ts +683 -0
  148. package/src/plugins/inner/common/danmu/lang.ts +139 -0
  149. package/src/plugins/inner/common/danmu/panel.ts +20 -0
  150. package/src/plugins/inner/common/danmu/slider.ts +210 -0
  151. package/src/plugins/inner/common/danmu/state.ts +118 -0
  152. package/src/plugins/inner/common/danmu/switch.ts +74 -0
  153. package/src/plugins/inner/common/definitionBasePlugin.ts +353 -0
  154. package/src/plugins/inner/common/errorPlugin.ts +544 -0
  155. package/src/plugins/inner/common/liveLogger.ts +137 -0
  156. package/src/plugins/inner/common/poster/index.less +66 -0
  157. package/src/plugins/inner/common/poster/index.ts +178 -0
  158. package/src/plugins/inner/common/refreshPlugin.ts +88 -0
  159. package/src/plugins/inner/common/rtmPlugin.ts +62 -0
  160. package/src/plugins/inner/common/toastPlugin.ts +90 -0
  161. package/src/plugins/inner/common/unmutePlugin.ts +133 -0
  162. package/src/plugins/inner/common/vodLogger.ts +80 -0
  163. package/src/plugins/inner/mobile/DefinitionMobilePlugin.ts +217 -0
  164. package/src/plugins/inner/mobile/LineMobilePlugins.ts +169 -0
  165. package/src/plugins/inner/mobile/MoreButtonPlugin.ts +176 -0
  166. package/src/plugins/inner/mobile/PlaybackRatePlugin.ts +199 -0
  167. package/src/plugins/inner/pc/definitionPlugin.ts +203 -0
  168. package/src/plugins/inner/pc/multilinePlugin.ts +93 -0
  169. package/src/sdkPlugin/abr.ts +67 -0
  170. package/src/sdkPlugin/adaptRange.ts +49 -0
  171. package/src/sdkPlugin/authToken.ts +557 -0
  172. package/src/sdkPlugin/sdkPlugin.ts +125 -0
  173. package/src/sdkPlugin/sdkPluginManager.ts +157 -0
  174. package/src/sdkPlugin/strategy.ts +47 -0
  175. package/src/strategy/index.ts +740 -0
  176. package/src/strategy/vestrategy-h265-wrapper.ts +34 -0
  177. package/src/strategy/vestrategy-preload-wrapper.ts +414 -0
  178. package/src/streamAdapters/base.ts +89 -0
  179. package/src/streamAdapters/dash.ts +230 -0
  180. package/src/streamAdapters/default.ts +53 -0
  181. package/src/streamAdapters/hls.ts +278 -0
  182. package/src/streamAdapters/index.ts +40 -0
  183. package/src/streamAdapters/mp4.ts +214 -0
  184. package/src/style/bytelive/danmu.less +293 -0
  185. package/src/style/bytelive/definitionIcon.less +80 -0
  186. package/src/style/bytelive/error.less +165 -0
  187. package/src/style/bytelive/index.less +62 -0
  188. package/src/style/bytelive/loading.less +5 -0
  189. package/src/style/bytelive/mobiePlugin.less +2 -0
  190. package/src/style/bytelive/mobile.less +76 -0
  191. package/src/style/bytelive/moreButton.less +79 -0
  192. package/src/style/bytelive/panel.less +259 -0
  193. package/src/style/bytelive/pc.less +161 -0
  194. package/src/style/bytelive/refresh.less +3 -0
  195. package/src/style/bytelive/reset.less +4 -0
  196. package/src/style/bytelive/toast.less +61 -0
  197. package/src/style/bytelive/unmute.less +65 -0
  198. package/src/style/external/LiveInfoPanel.less +41 -0
  199. package/src/style/external/aisub.less +139 -0
  200. package/src/style/external/aisubIcon.less +25 -0
  201. package/src/style/external/index.less +5 -0
  202. package/src/style/external/larkWindow.less +36 -0
  203. package/src/style/external/mirror.less +27 -0
  204. package/src/style/external/playList.less +258 -0
  205. package/src/style/external/timeShift.less +102 -0
  206. package/src/style/external/vttSubtitle.less +25 -0
  207. package/src/utils/debug.ts +62 -0
  208. package/src/utils/definition.ts +61 -0
  209. package/src/utils/escapeHtml.ts +93 -0
  210. package/src/utils/eventMiddleWare.ts +108 -0
  211. package/src/utils/index.ts +621 -0
  212. package/src/utils/intervalTimer.ts +38 -0
  213. package/src/utils/isHijackBrowser.ts +71 -0
  214. package/src/utils/proxy.ts +139 -0
  215. package/src/utils/storage.ts +34 -0
  216. package/src/utils/time.ts +19 -0
  217. package/src/utils/toast/index.less +20 -0
  218. package/src/utils/toast/index.ts +21 -0
  219. package/src/utils/token.ts +395 -0
  220. package/src/utils/u8a.ts +4 -0
  221. package/src/utils/umdLoader.ts +193 -0
  222. package/src/utils/video.ts +43 -0
  223. package/src/utils/xhr.ts +160 -0
  224. package/src/veError/error.ts +301 -0
  225. package/src/veError/index.ts +681 -0
  226. package/src/veError/playerProxy.ts +69 -0
  227. package/tsconfig.json +27 -0
  228. package/index.d.ts +0 -6874
  229. package/index.min.css +0 -1
  230. package/index.min.js +0 -2
  231. package/plugin/DashAbralgo.js +0 -2
  232. package/plugin/XGVideo.js +0 -2
  233. package/plugin/danmuMask.js +0 -2
  234. package/plugin/danmujs.js +0 -3
  235. package/plugin/dash.js +0 -2
  236. package/plugin/flv.js +0 -2
  237. package/plugin/hls.js +0 -2
  238. package/plugin/hlsEncrypt.js +0 -2
  239. package/plugin/mp4Encrypt.js +0 -2
  240. package/plugin/preloader.js +0 -2
  241. package/plugin/streamprobe.js +0 -2
  242. package/plugin/vestrategy.js +0 -1
  243. package/plugin/vestrategy_adapt_range.js +0 -1
  244. package/plugin/vestrategy_h265.js +0 -1
  245. package/plugin/vestrategy_preload.js +0 -1
@@ -0,0 +1,115 @@
1
+ import EventEmitter from 'eventemitter3';
2
+ import { VE_DEBUG } from '@/utils';
3
+
4
+ export default class NativeSubTitle extends EventEmitter {
5
+ public _media: any;
6
+ public _list: any[];
7
+ public _languages: string;
8
+ public curIndex: number;
9
+ constructor(media) {
10
+ super();
11
+ this._media = media;
12
+ this._list = [];
13
+ this._languages = '';
14
+ this.curIndex = -1;
15
+ this._init();
16
+ }
17
+
18
+ _init() {
19
+ const _list = this._media.textTracks;
20
+ if (_list) {
21
+ _list.addEventListener('change', this._onChange);
22
+ _list.addEventListener('addtrack', this._onChange);
23
+ } else {
24
+ VE_DEBUG.warn('current browser not support native subtitle');
25
+ }
26
+ }
27
+
28
+ _onChange = e => {
29
+ const _list = this._media.textTracks;
30
+ if (!_list || _list.length === 0) {
31
+ return;
32
+ }
33
+ const retList = [];
34
+ const langs = [];
35
+ let curIndex = -1;
36
+ for (let i = 0; i < _list.length; i++) {
37
+ const item = _list[i];
38
+ if (item.kind === 'subtitles') {
39
+ retList.push({
40
+ id: item.id || item.language,
41
+ language: item.language,
42
+ text: item.label,
43
+ isDefault: item.mode === 'showing',
44
+ });
45
+ if (curIndex === -1 && item.mode === 'showing') {
46
+ curIndex = i;
47
+ }
48
+ langs.push(item.language);
49
+ }
50
+ }
51
+
52
+ // 语言列表发生变化
53
+ if (langs.join('|') !== this._languages) {
54
+ this._languages = langs.join('|');
55
+ this.emit('reset', {
56
+ list: retList,
57
+ isOpen: curIndex > -1,
58
+ });
59
+ } else if (curIndex === -1) {
60
+ this.emit('off');
61
+ } else if (this.curIndex !== curIndex) {
62
+ this.emit('change', retList[curIndex]);
63
+ }
64
+ this.curIndex = curIndex;
65
+ };
66
+
67
+ /**
68
+ * @description 切换字幕
69
+ * @param { null | {
70
+ * id: any,
71
+ * language: any
72
+ * }} data
73
+ * @return {Promise<{code: number}>}
74
+ */
75
+ switch(data) {
76
+ return new Promise((resolve, reject) => {
77
+ if (!data) {
78
+ return reject({
79
+ code: 1,
80
+ message: 'no subtitle data',
81
+ });
82
+ }
83
+ const _tracks = this._media.textTracks;
84
+ for (let i = 0; i < _tracks.length; i++) {
85
+ const item = _tracks[i];
86
+ if (item.language === data.language) {
87
+ item.mode = 'showing';
88
+ // this.curIndex = i
89
+ } else if (item.mode === 'showing') {
90
+ item.mode = 'disabled';
91
+ }
92
+ }
93
+ return resolve({
94
+ code: 0,
95
+ });
96
+ });
97
+ }
98
+
99
+ switchOff() {
100
+ const _tracks = this._media.textTracks;
101
+ for (let i = 0; i < _tracks.length; i++) {
102
+ _tracks[i].mode = 'disabled';
103
+ }
104
+ this.curIndex = -1;
105
+ }
106
+
107
+ destroy() {
108
+ const _list = this._media.textTracks;
109
+ _list.removeEventListener('change', this._onChange);
110
+ this._media = null;
111
+ this._list = [];
112
+ this._languages = '';
113
+ this.curIndex = -1;
114
+ }
115
+ }
@@ -0,0 +1,484 @@
1
+ import { PluginEvents } from '@/constants/event';
2
+ import { Events, Plugin, Sniffer, Util } from 'xgplayer';
3
+ import { formatTime } from '../../utils/time';
4
+ import { addUrlParam } from '@/utils';
5
+ const { POSITIONS } = Plugin;
6
+
7
+ const UpperLimit = 7 * 24 * 3600; // 最大时移时间7天
8
+ const MinMoveTime = 6; // 最小时移6s
9
+
10
+ export default class TimeShiftPlugin extends Plugin {
11
+ static get pluginName() {
12
+ return 'TimeShiftPlugin';
13
+ }
14
+
15
+ static get defaultConfig() {
16
+ return {
17
+ position: POSITIONS.CONTROLS_CENTER,
18
+ livingStartTime: Date.now() / 1000,
19
+ maxMoveTime: 0,
20
+ currentTime: Date.now() / 1000,
21
+ timeShiftUrl: '',
22
+ cardList: [],
23
+ };
24
+ }
25
+
26
+ public isMobile = Sniffer.device === 'mobile';
27
+
28
+ public playedBar: any = null;
29
+ public cachedBar: any = null;
30
+ public innerBar: any = null;
31
+ public progressBtn: any = null;
32
+ public progressPoint: any = null;
33
+ public backLiveBt: any = null;
34
+ public cardDomList: any[] = [];
35
+
36
+ public initTime = 0; // 启播时的客户端时间
37
+ public liveGap = 0; // 初始直播时间差距
38
+ public shiftTimeGap = 0; // 相对latestLiveGap的时移时间
39
+
40
+ public isProgressMoving = false;
41
+ public isPlayTimeShift = false;
42
+ private liveUrl = '';
43
+
44
+ get duration() {
45
+ const latestLiveGap =
46
+ this.liveGap + Math.floor(Date.now() / 1000 - this.initTime);
47
+
48
+ const { maxMoveTime } = this.config ?? {};
49
+ // 如何设置最大回看时间
50
+ if (maxMoveTime && latestLiveGap > maxMoveTime) {
51
+ return maxMoveTime;
52
+ }
53
+
54
+ return latestLiveGap > UpperLimit ? UpperLimit : latestLiveGap;
55
+ }
56
+
57
+ registerLanguageTexts() {
58
+ return {
59
+ BACKLIVE: {
60
+ jp: 'ライブに戻る',
61
+ en: 'Back to live',
62
+ zh: '返回直播',
63
+ 'zh-hk': '返回直播',
64
+ },
65
+ };
66
+ }
67
+
68
+ updateLang() {
69
+ if (!this.backLiveBt) return;
70
+ this.backLiveBt.innerHTML = (this.langText as any).BACKLIVE;
71
+ }
72
+
73
+ afterCreate() {
74
+ this.liveUrl = this.player.config.url as string;
75
+
76
+ this.playedBar = this.find('.xgplayer-progress-played');
77
+ this.cachedBar = this.find('.xgplayer-progress-cache');
78
+ this.progressBtn = this.find('.xgplayer-progress-btn');
79
+ this.progressPoint = this.find('.xgplayer-shift-progress-point');
80
+ this.innerBar = this.find('.xgplayer-progress-inner');
81
+
82
+ this.createBackLiveBtDom();
83
+ this.clacTime();
84
+ this.initEvents();
85
+ this.bindDomEvents();
86
+
87
+ if (!this.isMobile) {
88
+ this.createTimeShiftCard();
89
+ }
90
+ }
91
+
92
+ clacTime() {
93
+ const { livingStartTime, currentTime } = this.config ?? {};
94
+ this.initTime = Math.floor(Date.now() / 1000);
95
+ this.liveGap = Math.floor(currentTime - livingStartTime);
96
+ }
97
+
98
+ initEvents() {
99
+ this.on(Events.TIME_UPDATE, this.handleTimeUpdate.bind(this));
100
+ }
101
+
102
+ bindDomEvents() {
103
+ this.handleMouseDown = this.handleMouseDown.bind(this);
104
+ this.handleMouseUp = this.handleMouseUp.bind(this);
105
+ this.handleMouseMove = this.handleMouseMove.bind(this);
106
+ this.handleMouseEnter = this.handleMouseEnter.bind(this);
107
+ this.handleMouseLeave = this.handleMouseLeave.bind(this);
108
+ this.tipsUpdate = this.tipsUpdate.bind(this);
109
+
110
+ if (this.isMobile) {
111
+ this.bind('touchstart', this.handleMouseDown);
112
+ const controls = this.player.controls;
113
+ if (controls) {
114
+ controls.root &&
115
+ controls.root.addEventListener('touchmove', Util.stopPropagation);
116
+ controls.center &&
117
+ controls.center.addEventListener('touchend', Util.stopPropagation);
118
+ }
119
+ } else {
120
+ this.bind('mousedown', this.handleMouseDown);
121
+ this.bind('mouseenter', this.handleMouseEnter);
122
+ }
123
+ }
124
+
125
+ handleTimeUpdate() {
126
+ if (this.isProgressMoving) {
127
+ return;
128
+ }
129
+ this.progressUpdate();
130
+ }
131
+
132
+ onBodyClick = (e: any) => {
133
+ e.preventDefault();
134
+ e.stopPropagation();
135
+ Util.event(e);
136
+ };
137
+
138
+ handleMouseDown(e: any) {
139
+ if (e.target === this.backLiveBt) {
140
+ return;
141
+ }
142
+
143
+ this.onBodyClick(e);
144
+
145
+ this.focus();
146
+ Util.addClass(this.progressBtn, 'active');
147
+ const pos = this.computeTime(e);
148
+ this.updateShiftTime(pos.percent);
149
+ this.isProgressMoving = true;
150
+
151
+ if (this.isMobile) {
152
+ this.bind('touchmove', this.handleMouseMove);
153
+ this.bind('touchend', this.handleMouseUp);
154
+ } else {
155
+ document.addEventListener('mousemove', this.handleMouseMove, false);
156
+ document.addEventListener('mouseup', this.handleMouseUp, false);
157
+ }
158
+ }
159
+
160
+ handleMouseMove(e: any) {
161
+ this.onBodyClick(e);
162
+
163
+ const pos = this.computeTime(e);
164
+ this.updateShiftTime(pos.percent);
165
+ }
166
+
167
+ handleMouseUp(e: any) {
168
+ this.onBodyClick(e);
169
+ this.isProgressMoving = false;
170
+ Util.removeClass(this.progressBtn, 'active');
171
+
172
+ this.changeTimeUrl();
173
+
174
+ if (this.isMobile) {
175
+ this.unbind('touchmove', this.handleMouseMove);
176
+ this.unbind('touchend', this.handleMouseUp);
177
+ } else {
178
+ document.removeEventListener('mousemove', this.handleMouseMove, false);
179
+ document.removeEventListener('mouseup', this.handleMouseUp, false);
180
+ }
181
+ }
182
+
183
+ handleMouseEnter(e: any) {
184
+ this.bind('mouseleave', this.handleMouseLeave);
185
+ this.bind('mousemove', this.tipsUpdate);
186
+
187
+ this.tipsUpdate(e);
188
+ this.focus();
189
+ }
190
+
191
+ handleMouseLeave() {
192
+ this.unbind('mouseleave', this.handleMouseLeave);
193
+ this.unbind('mousemove', this.tipsUpdate);
194
+ this.blur();
195
+ }
196
+
197
+ focus() {
198
+ this.player.controls.pauseAutoHide();
199
+ Util.addClass(this.root, 'active');
200
+ }
201
+
202
+ blur() {
203
+ this.player.controls.recoverAutoHide();
204
+ Util.removeClass(this.root, 'active');
205
+ }
206
+
207
+ computeTime(e: any) {
208
+ const { player } = this;
209
+ const { width, height, top, left } = this.root.getBoundingClientRect();
210
+ const _ePos = Util.getEventPos(e, player.zoom);
211
+ let rWidth, rLeft, clientX;
212
+ if (player.rotateDeg === 90) {
213
+ rWidth = height;
214
+ rLeft = top;
215
+ clientX = _ePos.clientY;
216
+ } else {
217
+ rWidth = width;
218
+ rLeft = left;
219
+ clientX = _ePos.clientX;
220
+ }
221
+ let offset = clientX - rLeft;
222
+ offset = offset > rWidth ? rWidth : offset < 0 ? 0 : offset;
223
+
224
+ let percent = offset / rWidth;
225
+ percent = percent < 0 ? 0 : percent > 1 ? 1 : percent;
226
+ return {
227
+ percent,
228
+ offset,
229
+ width: rWidth,
230
+ left: rLeft,
231
+ e,
232
+ };
233
+ }
234
+
235
+ tipsUpdate(e: any) {
236
+ const pos = this.computeTime(e);
237
+
238
+ const shiftTimeGap = Math.floor(this.duration * (1 - pos.percent));
239
+
240
+ this.progressPoint.style.left = `${pos.percent * 100}%`;
241
+
242
+ this.progressPoint.innerHTML = `-${formatTime(shiftTimeGap)}`;
243
+ }
244
+
245
+ updateShiftTime(percent: number) {
246
+ this.shiftTimeGap = Math.floor(this.duration * (1 - percent));
247
+ this.progressUpdate();
248
+ }
249
+
250
+ getCurrentProgress() {
251
+ return Math.floor(this.duration - this.shiftTimeGap);
252
+ }
253
+
254
+ progressUpdate() {
255
+ const progressNumber = this.getCurrentProgress();
256
+ const progressPercent = progressNumber / this.duration;
257
+ this.progressBtn.style.left = `${progressPercent * 100}%`;
258
+ this.playedBar.style.width = `${progressPercent * 100}%`;
259
+
260
+ this.cardProcessUpdate();
261
+ }
262
+
263
+ changeTimeShift(time) {
264
+ const progressPercent = this.calcCardProcess(time);
265
+ if (progressPercent < 0) return;
266
+ this.updateShiftTime(progressPercent);
267
+ this.changeTimeUrl();
268
+ }
269
+
270
+ changeTimeUrl() {
271
+ const { timeShiftUrl } = this.config;
272
+ let shiftUrl = '';
273
+
274
+ this.isPlayTimeShift = true;
275
+ this.toggleBackButton();
276
+ const shiftTimeGap =
277
+ this.shiftTimeGap < MinMoveTime ? MinMoveTime : this.shiftTimeGap;
278
+ if (!timeShiftUrl) {
279
+ shiftUrl = addUrlParam(this.liveUrl, {
280
+ timeshift: shiftTimeGap,
281
+ });
282
+ } else {
283
+ shiftUrl = timeShiftUrl.replace('{}', shiftTimeGap);
284
+ }
285
+
286
+ this.player.src = shiftUrl;
287
+ this.player.config.url = shiftUrl;
288
+ this.player.emit(PluginEvents.TIME_SHIFT_CHANGE, true);
289
+ this.player.emit(PluginEvents.PlAY_URL_CHANGE, {
290
+ shiftUrl,
291
+ from: PluginEvents.TIME_SHIFT_CHANGE,
292
+ });
293
+ }
294
+
295
+ createBackLiveBtDom() {
296
+ if (this.backLiveBt) {
297
+ return this.backLiveBt;
298
+ }
299
+
300
+ this.backLiveBt = Util.createDom(
301
+ 'xg-back-live-bt',
302
+ (this.langText as any).BACKLIVE,
303
+ undefined,
304
+ 'xgplayer-back-live-bt',
305
+ );
306
+
307
+ this.backLiveBt.addEventListener('click', (e: any) => {
308
+ this.onBodyClick(e);
309
+ this.backLive();
310
+ });
311
+
312
+ this.player.root?.appendChild(this.backLiveBt);
313
+ }
314
+
315
+ backLive() {
316
+ if (!this.liveUrl) {
317
+ return;
318
+ }
319
+
320
+ this.player.src = this.liveUrl;
321
+ this.player.config.url = this.liveUrl;
322
+ this.shiftTimeGap = 0;
323
+ this.isPlayTimeShift = false;
324
+ this.toggleBackButton();
325
+ this.player.emit(PluginEvents.TIME_SHIFT_CHANGE, false);
326
+ this.player.emit(PluginEvents.PlAY_URL_CHANGE, {
327
+ url: this.liveUrl,
328
+ from: PluginEvents.TIME_SHIFT_CHANGE,
329
+ });
330
+ }
331
+
332
+ toggleBackButton() {
333
+ if (!this.backLiveBt) return;
334
+ this.backLiveBt.style.display = this.isPlayTimeShift ? 'flex' : 'none';
335
+ }
336
+
337
+ updateCardList(cardList) {
338
+ this.config.cardList = [...cardList];
339
+ this.clearCardDom();
340
+ this.createTimeShiftCard();
341
+ }
342
+
343
+ clearCardDom() {
344
+ this.cardDomList.forEach(card => {
345
+ if (!card.dom) return;
346
+ if (this.innerBar.contains(card.dom)) {
347
+ this.innerBar.removeChild(card.dom);
348
+ }
349
+ });
350
+ this.cardDomList = [];
351
+ }
352
+
353
+ createTimeShiftCard() {
354
+ if (this.config.cardList?.length <= 0) return;
355
+ const cardList = this.config.cardList;
356
+ cardList.forEach(card => {
357
+ this.renderCard(card);
358
+ });
359
+ }
360
+
361
+ renderCard(card) {
362
+ if (!card.img) return;
363
+ const $card = Util.createDom(
364
+ 'xg-card',
365
+ '',
366
+ undefined,
367
+ 'xgplayer-shift-progress-card',
368
+ );
369
+ const $cardImg = Util.createDom(
370
+ 'img',
371
+ '',
372
+ { src: card.img },
373
+ 'xgplayer-shift-progress-card-img',
374
+ );
375
+
376
+ const $point = Util.createDom(
377
+ 'div',
378
+ '',
379
+ undefined,
380
+ 'xgplayer-shift-progress-card-point',
381
+ );
382
+ $card.appendChild($cardImg);
383
+ $card.appendChild($point);
384
+ this.cardDomList.push({
385
+ ...card,
386
+ dom: $card,
387
+ });
388
+ }
389
+
390
+ cardProcessUpdate() {
391
+ if (this.cardDomList.length === 0) return;
392
+ this.cardDomList.forEach(card => {
393
+ if (!card.dom) return;
394
+ const progressPercent = this.calcCardProcess(card.timestamp);
395
+ if (progressPercent > 1) {
396
+ return;
397
+ }
398
+ const isContains = this.innerBar.contains(card.dom);
399
+ if (progressPercent < 0) {
400
+ isContains && this.innerBar.removeChild(card.dom);
401
+ return;
402
+ }
403
+ if (!isContains) {
404
+ this.innerBar.appendChild(card.dom);
405
+ }
406
+ card.dom.style.left = `${progressPercent * 100}%`;
407
+ });
408
+ }
409
+
410
+ calcCardProcess(time) {
411
+ const { maxMoveTime, livingStartTime } = this.config ?? {};
412
+ let startingPointTime = livingStartTime;
413
+ const latestLiveGap =
414
+ this.liveGap + Math.floor(Date.now() / 1000 - this.initTime);
415
+ // 如过设置最大回看时间
416
+ if (maxMoveTime && latestLiveGap > maxMoveTime) {
417
+ startingPointTime = latestLiveGap - maxMoveTime;
418
+ }
419
+
420
+ if (time < startingPointTime) {
421
+ return -1;
422
+ }
423
+
424
+ return (time - startingPointTime) / this.duration;
425
+ }
426
+
427
+ // clickCardToTimeShift(time) {
428
+ // if (!time) return;
429
+ // const progressPercent = this.calcCardProcess(time);
430
+ // this.updateShiftTime(progressPercent);
431
+ // }
432
+
433
+ destroy() {
434
+ this.off(Events.TIME_UPDATE, this.handleTimeUpdate.bind(this));
435
+
436
+ if (this.isMobile) {
437
+ this.unbind('touchstart', this.handleMouseDown);
438
+ const controls = this.player.controls;
439
+ if (controls) {
440
+ controls.root &&
441
+ (controls.root as HTMLElement).removeEventListener(
442
+ 'touchmove',
443
+ Util.stopPropagation,
444
+ );
445
+ controls.center &&
446
+ controls.center.removeEventListener('touchend', Util.stopPropagation);
447
+ }
448
+ } else {
449
+ this.unbind('mousedown', this.handleMouseDown);
450
+ this.unbind('mouseenter', this.handleMouseEnter);
451
+ }
452
+
453
+ if (this.backLiveBt) {
454
+ this.player.root?.removeChild(this.backLiveBt);
455
+ this.backLiveBt = null;
456
+ }
457
+ }
458
+
459
+ render() {
460
+ if (this.config.disable) {
461
+ return '';
462
+ }
463
+ const controlsMode = this.player.controls
464
+ ? this.player.controls.config.mode
465
+ : '';
466
+ const className =
467
+ controlsMode === 'bottom' ? 'xgplayer-progress-bottom' : '';
468
+
469
+ return `
470
+ <xg-progress class="xgplayer-progress ${className} xgplayer-shift">
471
+ <xg-outer class="xgplayer-progress-outer">
472
+ <xg-inners class="progress-list">
473
+ <xg-inner class="xgplayer-progress-inner" style="flex: 1">
474
+ <xg-cache class="xgplayer-progress-cache" style="width: 100%;"></xg-cache>
475
+ <xg-played class="xgplayer-progress-played" style="width: 100%;"></xg-played>
476
+ </xg-inner>
477
+ </xg-inners>
478
+ <xg-progress-btn class="xgplayer-progress-btn"></xg-progress-btn>
479
+ <xg-point class="xgplayer-shift-progress-point">00:00</xg-point>
480
+ </xg-outer>
481
+ </xg-progress>
482
+ `;
483
+ }
484
+ }
@@ -0,0 +1,13 @@
1
+ @keyframes _xg_animation_blink {
2
+ 0% {
3
+ opacity: 0.1;
4
+ }
5
+
6
+ 50% {
7
+ opacity: 1;
8
+ }
9
+
10
+ 100% {
11
+ opacity: 0.1;
12
+ }
13
+ }