@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,132 @@
1
+ import { Events, Plugin, Sniffer } from 'xgplayer';
2
+ import Default from '../../assets/icons/pc/danmu.svg';
3
+ import debounce from 'lodash-es/debounce';
4
+ import { PluginEvents } from '../../constants/event';
5
+ import { EventPlugin } from '../../interface';
6
+
7
+ const { POSITIONS } = Plugin;
8
+
9
+ const extendPlugin = (options: EventPlugin): any => {
10
+ const isMobile = Sniffer.device === 'mobile';
11
+
12
+ const {
13
+ pluginName = `ExtendPlugin${Math.random().toString().slice(-5)}`,
14
+ type = isMobile ? 'inner' : 'normal',
15
+ position = POSITIONS.CONTROLS_LEFT,
16
+ icon = Default,
17
+ index = 1,
18
+ hideAtFullScreen = true,
19
+ tips = {
20
+ jp: 'custom',
21
+ en: 'custom',
22
+ zh: '自定义',
23
+ 'zh-hk': '自定义',
24
+ },
25
+ } = options;
26
+
27
+ return class ExtendPlugin extends Plugin {
28
+ static get isExtendPlugin() {
29
+ return true;
30
+ }
31
+
32
+ static get type() {
33
+ return type;
34
+ }
35
+
36
+ static get textTips() {
37
+ return tips;
38
+ }
39
+
40
+ static get pluginName() {
41
+ return pluginName;
42
+ }
43
+
44
+ static get defaultConfig() {
45
+ return {
46
+ position: position,
47
+ index: index,
48
+ };
49
+ }
50
+
51
+ afterCreate() {
52
+ this.appendChild('.xgplayer-icon', (this.icons as any)[pluginName]);
53
+ this.initEvents();
54
+ if (hideAtFullScreen && this.player?.fullscreen) {
55
+ this.handleFullScreenChange();
56
+ }
57
+ }
58
+
59
+ registerIcons() {
60
+ return {
61
+ [pluginName]: {
62
+ icon: icon,
63
+ class: 'xgplayer-extendicon-svg',
64
+ },
65
+ };
66
+ }
67
+
68
+ updateIcons(icon) {
69
+ const parent = this.find('.xgplayer-icon');
70
+ if (!parent) return;
71
+ parent.innerHTML = icon;
72
+ }
73
+
74
+ registerLanguageTexts() {
75
+ return {
76
+ [pluginName]: tips,
77
+ };
78
+ }
79
+
80
+ initEvents() {
81
+ this.handleCallback = debounce(this.handleCallback.bind(this), 200);
82
+ const event = Sniffer.device === 'mobile' ? 'touchend' : 'click';
83
+ this.bind(event, this.handleCallback);
84
+ this.show();
85
+
86
+ if (hideAtFullScreen) {
87
+ this.player?.on(
88
+ Events.FULLSCREEN_CHANGE,
89
+ this.handleFullScreenChange.bind(this),
90
+ );
91
+ }
92
+ }
93
+
94
+ handleFullScreenChange() {
95
+ const player: any = this.player;
96
+ (this.player as any)?.changePluginsIcon(pluginName, !player?.fullscreen);
97
+ }
98
+
99
+ handleCallback(e: any) {
100
+ const { player } = this;
101
+ if (!player) return;
102
+ e.preventDefault();
103
+ e.stopPropagation();
104
+
105
+ player.emit(PluginEvents.PLAYER_EXTEND_BUTTON, pluginName);
106
+ }
107
+
108
+ destroy() {
109
+ this.unbind(['touchend', 'click'], this.handleCallback);
110
+ if (hideAtFullScreen) {
111
+ this.player?.off(
112
+ Events.FULLSCREEN_CHANGE,
113
+ this.handleFullScreenChange.bind(this),
114
+ );
115
+ }
116
+ }
117
+
118
+ render() {
119
+ return `
120
+ <xg-icon class="xgplayer-extend-icon">
121
+ <div class="xgplayer-icon">
122
+ </div>
123
+ <div class="xg-tips" lang-key="${pluginName}">${
124
+ (this.langText as any)[pluginName]
125
+ }</div>
126
+ </xg-icon>
127
+ `;
128
+ }
129
+ };
130
+ };
131
+
132
+ export default extendPlugin;
@@ -0,0 +1,253 @@
1
+ import { PluginEvents } from '@/constants/event';
2
+ import { Events, Util } from 'xgplayer';
3
+ import { cancelTips, PLAYER_MODE } from '@/constants/player';
4
+
5
+ /**
6
+ * @hidden
7
+ * @brief 移动端交互面板配置
8
+ */
9
+ interface IConfig {
10
+ mode?: number;
11
+ isAutoChange?: boolean;
12
+ }
13
+
14
+ /**
15
+ * @hidden
16
+ * @brief 移动端交互面板
17
+ */
18
+ export default class MobilePlayerPanel {
19
+ public config: IConfig;
20
+ public parent: HTMLElement;
21
+ public root: any;
22
+ public mode: number;
23
+ public isAutoChange: number;
24
+ public player: any;
25
+ public children: HTMLElement | undefined;
26
+ public container: HTMLElement | undefined;
27
+ public title: HTMLElement | undefined;
28
+ // panel是否展示
29
+ public isShow: boolean;
30
+ public showCancelBtn: boolean;
31
+
32
+ constructor(args: any) {
33
+ const { config, root, player } = args;
34
+ this.config = config;
35
+ this.parent = root;
36
+ this.player = player;
37
+ let userMode = config?.mode ?? PLAYER_MODE.INNER;
38
+ if (!Object.values(PLAYER_MODE).includes(userMode)) {
39
+ userMode = PLAYER_MODE.INNER;
40
+ }
41
+ this.mode = userMode;
42
+ this.isAutoChange = config?.isAutoChange ?? false;
43
+ this.isShow = false;
44
+ this.showCancelBtn = config?.showCancelBtn ?? false;
45
+
46
+ this.initEvents();
47
+ this.renderPanel();
48
+ }
49
+
50
+ initEvents() {
51
+ if (!this.isAutoChange) return;
52
+ window.addEventListener(
53
+ 'orientationchange',
54
+ this.handleOrientationChange.bind(this),
55
+ );
56
+ this.player?.on(
57
+ Events.FULLSCREEN_CHANGE,
58
+ this.handleOrientationChange.bind(this),
59
+ );
60
+ }
61
+
62
+ handleOrientationChange() {
63
+ const isHorizontal = [90, -90, '90', '-90'].includes(window.orientation);
64
+ if (this.player?.fullscreen && isHorizontal) {
65
+ this.changeMode(PLAYER_MODE.FULLSCREEN);
66
+ } else {
67
+ this.changeMode(this.config?.mode ?? PLAYER_MODE.INNER);
68
+ }
69
+ }
70
+
71
+ changeConfig(config: IConfig) {
72
+ this.config = config;
73
+ }
74
+
75
+ changeMode(mode: number) {
76
+ this.mode = mode;
77
+ this.player.emit(PluginEvents.PANEL_MODE_CHANGE, {
78
+ mode: mode,
79
+ });
80
+ this.destroy();
81
+ this.renderPanel();
82
+ }
83
+
84
+ renderPanel() {
85
+ const classNameMap = ['normal', 'inner', 'fullscreen'];
86
+
87
+ const className = `xg-mobile-panel panel-${classNameMap[this.mode]}`;
88
+
89
+ this.root = Util.createDom('div', '', {}, className);
90
+
91
+ if (this.parent) {
92
+ this.parent.appendChild(this.root);
93
+ this.hide();
94
+ }
95
+
96
+ this.bind('click', this.handleHide.bind(this));
97
+
98
+ switch (this.mode) {
99
+ case PLAYER_MODE.NORMAL: {
100
+ const inner = Util.createDom(
101
+ 'div',
102
+ '',
103
+ {},
104
+ `xg-mobile-panel-content ${
105
+ this.showCancelBtn ? 'xg-mobile-panel-cancel-mode' : ''
106
+ }`,
107
+ );
108
+ this.root.appendChild(inner);
109
+ if (this.showCancelBtn) {
110
+ const lang = this.player.lang === 'zh-cn' ? 'zh' : this.player.lang;
111
+ const close = Util.createDom(
112
+ 'div',
113
+ cancelTips[lang],
114
+ {},
115
+ 'xg-mobile-panel-cancel',
116
+ );
117
+ this.root.appendChild(close);
118
+ }
119
+ this.container = inner;
120
+ inner.addEventListener('click', e => {
121
+ e.stopPropagation();
122
+ e.preventDefault();
123
+ });
124
+ break;
125
+ }
126
+ case PLAYER_MODE.INNER: {
127
+ this.container = this.root;
128
+ break;
129
+ }
130
+ case PLAYER_MODE.FULLSCREEN: {
131
+ const inner = Util.createDom('div', '', {}, 'xg-mobile-panel-content');
132
+ this.root.appendChild(inner);
133
+ this.container = inner;
134
+ inner.addEventListener('click', e => {
135
+ e.stopPropagation();
136
+ e.preventDefault();
137
+ });
138
+ break;
139
+ }
140
+ }
141
+ }
142
+
143
+ async showPanel(children: HTMLElement, title = '', isItemList = false) {
144
+ if (isItemList) {
145
+ Util.addClass(children, 'item-list-panel-content');
146
+ }
147
+
148
+ this.setTitle(title);
149
+
150
+ if (this.children) {
151
+ await this.hide();
152
+ setTimeout(() => {
153
+ this.children = children;
154
+ if (this.container) {
155
+ this.title && this.container.appendChild(this.title);
156
+ this.container.appendChild(children);
157
+ }
158
+ this.show();
159
+ });
160
+ return;
161
+ }
162
+
163
+ this.children = children;
164
+
165
+ if (this.container) {
166
+ this.title && this.container.appendChild(this.title);
167
+ this.container.appendChild(children);
168
+ }
169
+ this.show();
170
+ }
171
+
172
+ updatePanel(children: HTMLElement) {
173
+ if (
174
+ this.children &&
175
+ Util.hasClass(this.children, 'item-list-panel-content')
176
+ ) {
177
+ Util.addClass(children, 'item-list-panel-content');
178
+ }
179
+
180
+ this.children = children;
181
+
182
+ if (this.container) {
183
+ this.container.innerHTML = '';
184
+ this.title && this.container.appendChild(this.title);
185
+ this.container.appendChild(children);
186
+ }
187
+ }
188
+
189
+ setTitle(title) {
190
+ if (!title || this.mode === PLAYER_MODE.INNER) {
191
+ this.title = undefined;
192
+ return;
193
+ }
194
+
195
+ if (!this.title) {
196
+ this.title = this.renderTitle(title);
197
+ return;
198
+ }
199
+
200
+ this.title.innerHTML = title;
201
+ }
202
+
203
+ renderTitle(title) {
204
+ const $title = Util.createDom('div', title, {}, 'xg-mobile-panel-title');
205
+ return $title;
206
+ }
207
+
208
+ show() {
209
+ this.isShow = true;
210
+ Util.removeClass(this.root, 'hide');
211
+ Util.addClass(this.root, 'active');
212
+ }
213
+
214
+ hide() {
215
+ this.isShow = false;
216
+ Util.removeClass(this.root, 'active');
217
+ Util.addClass(this.root, 'hide');
218
+ if (this.container) {
219
+ this.container.innerHTML = '';
220
+ }
221
+ }
222
+
223
+ handleHide(e: any) {
224
+ e.stopPropagation();
225
+ e.preventDefault();
226
+ this.hide();
227
+ }
228
+
229
+ bind(event: string, eventHandle: any, isBubble = false) {
230
+ if (!this.root) {
231
+ return;
232
+ }
233
+ if (`on${event}` in this.root && typeof eventHandle === 'function') {
234
+ this.root.addEventListener(event, eventHandle, isBubble);
235
+ }
236
+ }
237
+
238
+ destroy() {
239
+ if (this.parent && this.root && this.parent.contains(this.root)) {
240
+ this.parent.removeChild(this.root);
241
+ this.root = null;
242
+ }
243
+
244
+ window.removeEventListener(
245
+ 'orientationchange',
246
+ this.handleOrientationChange.bind(this),
247
+ );
248
+ this.player?.off(
249
+ Events.FULLSCREEN_CHANGE,
250
+ this.handleOrientationChange.bind(this),
251
+ );
252
+ }
253
+ }
@@ -0,0 +1,340 @@
1
+ import { Plugin, Util } from 'xgplayer';
2
+ import util from 'xgplayer/es/utils/util';
3
+
4
+ type InfoItem = {
5
+ key: string;
6
+ label: string;
7
+ labelTextKey?: string;
8
+ value?: any;
9
+ render?: (key: any) => string;
10
+ type?: string;
11
+ dom?: Element;
12
+ };
13
+ /**
14
+ * 直播信息面板
15
+ */
16
+ export default class LiveInfoPanel extends Plugin {
17
+ private _pollTimer;
18
+ private _infoItems = [];
19
+
20
+ static get pluginName() {
21
+ return 'LiveInfoPanel';
22
+ }
23
+
24
+ static get defaultConfig() {
25
+ return {
26
+ visible: true,
27
+ showH265Info: false,
28
+ };
29
+ }
30
+
31
+ get streamType() {
32
+ return this.playerConfig.playerData.getCurrentStreamType();
33
+ }
34
+
35
+ afterCreate() {
36
+ if (!['flv', 'hls'].includes(this.streamType)) {
37
+ this.close();
38
+ return;
39
+ }
40
+
41
+ this.player.on('error', () => this._handleError());
42
+ this.player.on('loadeddata', () => this._handleLoadedData());
43
+ }
44
+
45
+ registerLanguageTexts() {
46
+ return {
47
+ DECODEFPS: {
48
+ en: 'decodeFps',
49
+ zh: '解码效率',
50
+ },
51
+ DECODECOST: {
52
+ en: 'decodeCost',
53
+ zh: '解码消耗',
54
+ },
55
+ FORMAT: {
56
+ en: 'format',
57
+ zh: '格式',
58
+ },
59
+ FPS: {
60
+ en: 'fps',
61
+ zh: '帧率',
62
+ },
63
+ BITRATE: {
64
+ en: 'birate',
65
+ zh: '码率',
66
+ },
67
+ GOP: {
68
+ en: 'GOP',
69
+ zh: 'GOP',
70
+ },
71
+ RESOLUTION: {
72
+ en: 'resolution',
73
+ zh: '分辨率',
74
+ },
75
+ ENCODETYPE: {
76
+ en: 'encodeType',
77
+ zh: '编码方式',
78
+ },
79
+ BUFFEREND: {
80
+ en: 'bufferEnd',
81
+ zh: 'buffer水位',
82
+ },
83
+ CURRENTTIME: {
84
+ en: 'currentTime',
85
+ zh: '播放进度',
86
+ },
87
+ };
88
+ }
89
+
90
+ _getDefaultInfo(data): Record<string, InfoItem> {
91
+ const softDecodeData = {
92
+ h265Title: {
93
+ key: 'h265Title',
94
+ label: 'H265解码',
95
+ type: 'title',
96
+ },
97
+ decodeEfficiency: {
98
+ key: 'decodeEfficiency',
99
+ label: '解码效率',
100
+ labelTextKey: 'DECODEFPS',
101
+ value: data.decodeFps,
102
+ render: value => value + 'frames/s',
103
+ },
104
+ decodeCost: {
105
+ key: 'decodeCost',
106
+ label: '解码消耗',
107
+ labelTextKey: 'DECODECOST',
108
+ value: data.decodeFps,
109
+ render: value => (value ? (1000 / value).toFixed() + 'ms' : ''),
110
+ },
111
+ };
112
+ return {
113
+ format: {
114
+ key: 'format',
115
+ label: '格式',
116
+ labelTextKey: 'FORMAT',
117
+ value: data.format,
118
+ },
119
+ framerate: {
120
+ key: 'framerate',
121
+ label: '帧率',
122
+ labelTextKey: 'FPS',
123
+ value: data.fps,
124
+ render: value => `${value} fps`,
125
+ },
126
+ bitrate: {
127
+ key: 'bitrate',
128
+ label: '码率',
129
+ labelTextKey: 'BITRATE',
130
+ value: data.bitrate,
131
+ render: value => `${value / 1000} kbps`,
132
+ },
133
+ gop: {
134
+ key: 'gop',
135
+ label: 'GOP',
136
+ labelTextKey: 'GOP',
137
+ value: data.gop,
138
+ render: value => `${value} frames`,
139
+ },
140
+ resolution: {
141
+ key: 'resolution',
142
+ label: '视频分辨率',
143
+ labelTextKey: 'RESOLUTION',
144
+ value: { width: data.width, height: data.height },
145
+ render: value => `${value.width} * ${value.height}`,
146
+ },
147
+ encodeType: {
148
+ key: 'encodeType',
149
+ label: '编码方式',
150
+ labelTextKey: 'ENCODETYPE',
151
+ value: data.encodeType,
152
+ },
153
+ bufferEnd: {
154
+ key: 'bufferEnd',
155
+ label: 'buffer水位',
156
+ labelTextKey: 'BUFFEREND',
157
+ value: data.bufferEnd,
158
+ },
159
+ currentTime: {
160
+ key: 'currentTime',
161
+ label: '播放进度',
162
+ labelTextKey: 'CURRENTTIME',
163
+ value: data.currentTime,
164
+ render: value => (value ? value.toFixed(6) + 's' : ''),
165
+ },
166
+ ...(data.isOpenSoftDecoding && this.config.showH265Info
167
+ ? softDecodeData
168
+ : {}),
169
+ };
170
+ }
171
+
172
+ _init() {
173
+ const originData = this._initDom(this._getInfoListData());
174
+ // TODO 去掉Proxy
175
+ this._infoItems = new Proxy(originData, {
176
+ set: (target, propKey, value) => {
177
+ this._updateDom(target[propKey].dom, value);
178
+ return Reflect.set(target, propKey, value);
179
+ },
180
+ });
181
+ this._tick();
182
+ }
183
+
184
+ _getStats() {
185
+ if (this.streamType === 'flv') {
186
+ return this.player.plugins.flv?.getStats();
187
+ } else if (this.streamType === 'hls') {
188
+ return this.player.plugins.hls?.getStats();
189
+ }
190
+ return {};
191
+ }
192
+
193
+ _getInfoListData() {
194
+ const stats = this._getStats() || {};
195
+ return this._getDefaultInfo(
196
+ Object.assign(stats, {
197
+ format: `${this.streamType}_live`,
198
+ isOpenSoftDecoding: this.playerConfig.mediaType == 'live-video',
199
+ }),
200
+ );
201
+ }
202
+
203
+ _initDom(infoItems) {
204
+ const container = this.find('.veplayer-livepanel-container');
205
+ container.innerHTML = '';
206
+
207
+ Object.values(infoItems).forEach((element: any) => {
208
+ const rowDom = Util.createDom(
209
+ 'veplayer-livepanel-div',
210
+ '',
211
+ undefined,
212
+ 'veplayer-livepanel-container-row',
213
+ );
214
+ if (element.type === 'title') {
215
+ this._updateTitle(rowDom, element);
216
+ } else {
217
+ this._updateDom(rowDom, element);
218
+ }
219
+ container.appendChild(rowDom);
220
+ element.dom = rowDom;
221
+ });
222
+
223
+ return infoItems;
224
+ }
225
+
226
+ _updateTitle(rowDom: Element, item: InfoItem) {
227
+ rowDom.innerHTML = '';
228
+ const labelSpan = Util.createDom(
229
+ 'veplayer-livepanel-span',
230
+ item.label,
231
+ undefined,
232
+ 'veplayer-livepanel-container-row-title',
233
+ );
234
+ rowDom.appendChild(labelSpan);
235
+ }
236
+
237
+ _updateDom(rowdom: Element, newItem: InfoItem) {
238
+ rowdom.innerHTML = '';
239
+ const labelSpan = Util.createDom(
240
+ 'veplayer-livepanel-span',
241
+ this._renderLabel(newItem),
242
+ undefined,
243
+ 'veplayer-livepanel-container-row-label',
244
+ );
245
+ rowdom.appendChild(labelSpan);
246
+ if (newItem.type !== 'title') {
247
+ const valueSpan = Util.createDom(
248
+ 'veplayer-livepanel-span',
249
+ this._renderValue(newItem),
250
+ );
251
+ rowdom.appendChild(valueSpan);
252
+ }
253
+ }
254
+
255
+ _renderLabel(item: InfoItem) {
256
+ return item.labelTextKey && this.langText[item.labelTextKey];
257
+ }
258
+
259
+ _renderValue(item: InfoItem) {
260
+ if (item.render) {
261
+ return item.render(item.value);
262
+ }
263
+ return item.value;
264
+ }
265
+
266
+ _handleDataChange() {
267
+ const newInfoItems = this._getInfoListData();
268
+ Object.values(this._infoItems).forEach((item: InfoItem) => {
269
+ // 判断新获取的数据下展示需要变化
270
+ if (
271
+ item.type !== 'title' &&
272
+ this._renderValue(item) !== this._renderValue(newInfoItems[item.key])
273
+ ) {
274
+ this._infoItems[item.key] = {
275
+ ...item,
276
+ ...newInfoItems[item.key],
277
+ };
278
+ }
279
+ });
280
+ }
281
+
282
+ _tick() {
283
+ this._pollTimer = setTimeout(() => {
284
+ clearTimeout(this._pollTimer);
285
+ this._poll();
286
+ this._tick();
287
+ }, 500);
288
+ }
289
+
290
+ _poll() {
291
+ this._handleDataChange();
292
+ }
293
+
294
+ destroy() {
295
+ clearTimeout(this._pollTimer);
296
+ }
297
+
298
+ _handleError() {
299
+ this._close();
300
+ }
301
+
302
+ _handleLoadedData() {
303
+ if (this.config.visible) {
304
+ this._open();
305
+ }
306
+ }
307
+
308
+ _open() {
309
+ const container = this.find('.veplayer-livepanel-container');
310
+ Util.removeClass(container as any, 'veplayer-livepanel-hidden');
311
+ this._init();
312
+ }
313
+
314
+ _close() {
315
+ const container = this.find('.veplayer-livepanel-container');
316
+ util.addClass(container as any, 'veplayer-livepanel-hidden');
317
+ clearTimeout(this._pollTimer);
318
+ }
319
+
320
+ // API
321
+ open() {
322
+ this._open();
323
+ this.config.visible = true;
324
+ }
325
+
326
+ close() {
327
+ this._close();
328
+ this.config.visible = false;
329
+ }
330
+
331
+ render() {
332
+ return `
333
+ <xg-livepanel class="xgplayer-livepanel">
334
+ <xg-livepanel-container class="veplayer-livepanel-container ${
335
+ !this.config.visible && 'veplayer-livepanel-hidden'
336
+ }">
337
+ </xg-livepanel-container></xg-livepanel>
338
+ `;
339
+ }
340
+ }
@@ -0,0 +1 @@
1
+ export { default } from '@byted/xgplayer-ve-ads';