feat(video-player): 添加移动网络流量消耗警告功能
当检测到用户使用移动网络且视频文件较大时,显示流量消耗警告弹窗 新增网络类型检测功能,支持微信内置浏览器环境 重构播放逻辑,统一通过requestPlay处理播放请求
Showing
2 changed files
with
248 additions
and
6 deletions
| ... | @@ -38,6 +38,17 @@ | ... | @@ -38,6 +38,17 @@ |
| 38 | </div> | 38 | </div> |
| 39 | </div> | 39 | </div> |
| 40 | 40 | ||
| 41 | + <div v-if="trafficWarnVisible && !showErrorOverlay" class="traffic-overlay"> | ||
| 42 | + <div class="traffic-content"> | ||
| 43 | + <div class="traffic-title">当前为移动网络</div> | ||
| 44 | + <div class="traffic-message">{{ `视频大小约:${trafficFileSizeText},注意流量消耗` }}</div> | ||
| 45 | + <div class="traffic-actions"> | ||
| 46 | + <button class="traffic-cancel" @click="cancelTrafficWarn">取消</button> | ||
| 47 | + <button class="traffic-confirm" @click="confirmTrafficWarn">继续播放</button> | ||
| 48 | + </div> | ||
| 49 | + </div> | ||
| 50 | + </div> | ||
| 51 | + | ||
| 41 | <!-- 错误提示覆盖层 --> | 52 | <!-- 错误提示覆盖层 --> |
| 42 | <div v-if="showErrorOverlay" class="error-overlay"> | 53 | <div v-if="showErrorOverlay" class="error-overlay"> |
| 43 | <div class="error-content"> | 54 | <div class="error-content"> |
| ... | @@ -99,9 +110,13 @@ const { | ... | @@ -99,9 +110,13 @@ const { |
| 99 | errorMessage, | 110 | errorMessage, |
| 100 | showNetworkSpeedOverlay, | 111 | showNetworkSpeedOverlay, |
| 101 | networkSpeedText, | 112 | networkSpeedText, |
| 113 | + trafficWarnVisible, | ||
| 114 | + trafficFileSizeText, | ||
| 115 | + confirmTrafficWarn, | ||
| 116 | + cancelTrafficWarn, | ||
| 117 | + requestPlay, | ||
| 102 | retryLoad, | 118 | retryLoad, |
| 103 | handleVideoJsMounted, | 119 | handleVideoJsMounted, |
| 104 | - tryNativePlay | ||
| 105 | } = useVideoPlayer(props, emit, videoRef, nativeVideoRef); | 120 | } = useVideoPlayer(props, emit, videoRef, nativeVideoRef); |
| 106 | 121 | ||
| 107 | // 事件处理 | 122 | // 事件处理 |
| ... | @@ -134,10 +149,10 @@ defineExpose({ | ... | @@ -134,10 +149,10 @@ defineExpose({ |
| 134 | }, | 149 | }, |
| 135 | play() { | 150 | play() { |
| 136 | if (useNativePlayer.value) { | 151 | if (useNativePlayer.value) { |
| 137 | - tryNativePlay(); | 152 | + void requestPlay(false); |
| 138 | return; | 153 | return; |
| 139 | } | 154 | } |
| 140 | - player.value?.play()?.catch(console.warn); | 155 | + void requestPlay(false); |
| 141 | }, | 156 | }, |
| 142 | getPlayer() { | 157 | getPlayer() { |
| 143 | return useNativePlayer.value ? nativeVideoRef.value : player.value; | 158 | return useNativePlayer.value ? nativeVideoRef.value : player.value; |
| ... | @@ -233,6 +248,70 @@ defineExpose({ | ... | @@ -233,6 +248,70 @@ defineExpose({ |
| 233 | opacity: 0.95; | 248 | opacity: 0.95; |
| 234 | } | 249 | } |
| 235 | 250 | ||
| 251 | +.traffic-overlay { | ||
| 252 | + position: absolute; | ||
| 253 | + top: 0; | ||
| 254 | + left: 0; | ||
| 255 | + right: 0; | ||
| 256 | + bottom: 0; | ||
| 257 | + display: flex; | ||
| 258 | + align-items: center; | ||
| 259 | + justify-content: center; | ||
| 260 | + z-index: 950; | ||
| 261 | + pointer-events: auto; | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | +.traffic-content { | ||
| 265 | + padding: 16px 18px; | ||
| 266 | + border-radius: 12px; | ||
| 267 | + background: rgba(0, 0, 0, 0.75); | ||
| 268 | + backdrop-filter: blur(12px); | ||
| 269 | + color: #fff; | ||
| 270 | + text-align: center; | ||
| 271 | + max-width: 86%; | ||
| 272 | +} | ||
| 273 | + | ||
| 274 | +.traffic-title { | ||
| 275 | + font-size: 16px; | ||
| 276 | + font-weight: 600; | ||
| 277 | + line-height: 1.2; | ||
| 278 | + margin-bottom: 8px; | ||
| 279 | +} | ||
| 280 | + | ||
| 281 | +.traffic-message { | ||
| 282 | + font-size: 14px; | ||
| 283 | + line-height: 1.4; | ||
| 284 | + opacity: 0.95; | ||
| 285 | + margin-bottom: 14px; | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +.traffic-actions { | ||
| 289 | + display: flex; | ||
| 290 | + align-items: center; | ||
| 291 | + justify-content: center; | ||
| 292 | + gap: 12px; | ||
| 293 | +} | ||
| 294 | + | ||
| 295 | +.traffic-cancel, | ||
| 296 | +.traffic-confirm { | ||
| 297 | + border: none; | ||
| 298 | + padding: 10px 14px; | ||
| 299 | + border-radius: 10px; | ||
| 300 | + cursor: pointer; | ||
| 301 | + font-size: 14px; | ||
| 302 | + line-height: 1; | ||
| 303 | +} | ||
| 304 | + | ||
| 305 | +.traffic-cancel { | ||
| 306 | + background: rgba(255, 255, 255, 0.15); | ||
| 307 | + color: rgba(255, 255, 255, 0.95); | ||
| 308 | +} | ||
| 309 | + | ||
| 310 | +.traffic-confirm { | ||
| 311 | + background: #007bff; | ||
| 312 | + color: #fff; | ||
| 313 | +} | ||
| 314 | + | ||
| 236 | .retry-button { | 315 | .retry-button { |
| 237 | background: #007bff; | 316 | background: #007bff; |
| 238 | color: white; | 317 | color: white; | ... | ... |
| ... | @@ -34,6 +34,11 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -34,6 +34,11 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 34 | const hasEverPlayed = ref(false); | 34 | const hasEverPlayed = ref(false); |
| 35 | let networkSpeedTimer = null; | 35 | let networkSpeedTimer = null; |
| 36 | 36 | ||
| 37 | + const networkKind = ref('unknown'); | ||
| 38 | + const trafficWarnVisible = ref(false); | ||
| 39 | + const trafficWarnAcknowledged = ref(false); | ||
| 40 | + let trafficWarnDuringAutoplay = false; | ||
| 41 | + | ||
| 37 | // 原生播放器状态 | 42 | // 原生播放器状态 |
| 38 | const nativeReady = ref(false); | 43 | const nativeReady = ref(false); |
| 39 | let nativeListeners = null; | 44 | let nativeListeners = null; |
| ... | @@ -100,6 +105,12 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -100,6 +105,12 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 100 | return String(size) + "B"; | 105 | return String(size) + "B"; |
| 101 | }; | 106 | }; |
| 102 | 107 | ||
| 108 | + const trafficFileSizeText = computed(() => { | ||
| 109 | + const len = probeInfo.value.content_length; | ||
| 110 | + if (!len) return "未知"; | ||
| 111 | + return formatBytes(len) || "未知"; | ||
| 112 | + }); | ||
| 113 | + | ||
| 103 | const getErrorHint = () => { | 114 | const getErrorHint = () => { |
| 104 | if (probeInfo.value.status === 403) return "(403:无权限或已过期)"; | 115 | if (probeInfo.value.status === 403) return "(403:无权限或已过期)"; |
| 105 | if (probeInfo.value.status === 404) return "(404:资源不存在)"; | 116 | if (probeInfo.value.status === 404) return "(404:资源不存在)"; |
| ... | @@ -113,6 +124,52 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -113,6 +124,52 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 113 | return ""; | 124 | return ""; |
| 114 | }; | 125 | }; |
| 115 | 126 | ||
| 127 | + const detectNetworkKind = async () => { | ||
| 128 | + if (typeof navigator === 'undefined') { | ||
| 129 | + networkKind.value = 'unknown'; | ||
| 130 | + return; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; | ||
| 134 | + const connectionType = connection && typeof connection.type === 'string' ? connection.type : ''; | ||
| 135 | + if (connectionType) { | ||
| 136 | + if (connectionType === 'wifi') { | ||
| 137 | + networkKind.value = 'wifi'; | ||
| 138 | + return; | ||
| 139 | + } | ||
| 140 | + if (connectionType === 'cellular') { | ||
| 141 | + networkKind.value = 'cellular'; | ||
| 142 | + return; | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + const effectiveType = connection && typeof connection.effectiveType === 'string' ? connection.effectiveType : ''; | ||
| 147 | + if (effectiveType) { | ||
| 148 | + if (effectiveType === '4g' || effectiveType === '3g' || effectiveType === '2g' || effectiveType === 'slow-2g') { | ||
| 149 | + networkKind.value = 'cellular'; | ||
| 150 | + return; | ||
| 151 | + } | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + if (typeof window !== 'undefined' && window.WeixinJSBridge) { | ||
| 155 | + await new Promise((resolve) => { | ||
| 156 | + try { | ||
| 157 | + window.WeixinJSBridge.invoke('getNetworkType', {}, (res) => { | ||
| 158 | + const wxType = (res && (res.networkType || res.err_msg || '')).toString().toLowerCase(); | ||
| 159 | + if (wxType.includes('wifi')) networkKind.value = 'wifi'; | ||
| 160 | + else if (wxType.includes('2g') || wxType.includes('3g') || wxType.includes('4g') || wxType.includes('5g')) networkKind.value = 'cellular'; | ||
| 161 | + resolve(); | ||
| 162 | + }); | ||
| 163 | + } catch (e) { | ||
| 164 | + resolve(); | ||
| 165 | + } | ||
| 166 | + }); | ||
| 167 | + return; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + networkKind.value = 'unknown'; | ||
| 171 | + }; | ||
| 172 | + | ||
| 116 | // 资源探测 | 173 | // 资源探测 |
| 117 | const probeVideo = async () => { | 174 | const probeVideo = async () => { |
| 118 | const url = videoUrlValue.value; | 175 | const url = videoUrlValue.value; |
| ... | @@ -182,6 +239,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -182,6 +239,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 182 | const handleError = (code, message = '') => { | 239 | const handleError = (code, message = '') => { |
| 183 | showErrorOverlay.value = true; | 240 | showErrorOverlay.value = true; |
| 184 | showNetworkSpeedOverlay.value = false; | 241 | showNetworkSpeedOverlay.value = false; |
| 242 | + trafficWarnVisible.value = false; | ||
| 185 | if (networkSpeedTimer) { | 243 | if (networkSpeedTimer) { |
| 186 | clearInterval(networkSpeedTimer); | 244 | clearInterval(networkSpeedTimer); |
| 187 | networkSpeedTimer = null; | 245 | networkSpeedTimer = null; |
| ... | @@ -230,6 +288,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -230,6 +288,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 230 | const showNetworkSpeed = () => { | 288 | const showNetworkSpeed = () => { |
| 231 | if (!hasEverPlayed.value) return; | 289 | if (!hasEverPlayed.value) return; |
| 232 | if (showErrorOverlay.value) return; | 290 | if (showErrorOverlay.value) return; |
| 291 | + if (trafficWarnVisible.value) return; | ||
| 233 | if (showNetworkSpeedOverlay.value) return; | 292 | if (showNetworkSpeedOverlay.value) return; |
| 234 | 293 | ||
| 235 | showNetworkSpeedOverlay.value = true; | 294 | showNetworkSpeedOverlay.value = true; |
| ... | @@ -249,6 +308,62 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -249,6 +308,62 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 249 | } | 308 | } |
| 250 | }; | 309 | }; |
| 251 | 310 | ||
| 311 | + const isOnWifi = computed(() => networkKind.value === 'wifi'); | ||
| 312 | + const isOnCellular = computed(() => networkKind.value === 'cellular'); | ||
| 313 | + | ||
| 314 | + const trafficWarnThresholdBytes = 200 * 1024 * 1024; | ||
| 315 | + | ||
| 316 | + const needTrafficWarn = computed(() => { | ||
| 317 | + if (isOnWifi.value) return false; | ||
| 318 | + if (!isOnCellular.value) return false; | ||
| 319 | + const len = probeInfo.value.content_length; | ||
| 320 | + if (!len) return false; | ||
| 321 | + return len >= trafficWarnThresholdBytes; | ||
| 322 | + }); | ||
| 323 | + | ||
| 324 | + const openTrafficWarn = async (fromAutoplay) => { | ||
| 325 | + if (trafficWarnAcknowledged.value) return false; | ||
| 326 | + trafficWarnDuringAutoplay = Boolean(fromAutoplay); | ||
| 327 | + | ||
| 328 | + if (!probeInfo.value.content_length && !probeLoading.value) { | ||
| 329 | + await probeVideo(); | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + if (!needTrafficWarn.value) return false; | ||
| 333 | + trafficWarnVisible.value = true; | ||
| 334 | + hideNetworkSpeed(); | ||
| 335 | + return true; | ||
| 336 | + }; | ||
| 337 | + | ||
| 338 | + const closeTrafficWarn = () => { | ||
| 339 | + trafficWarnVisible.value = false; | ||
| 340 | + trafficWarnDuringAutoplay = false; | ||
| 341 | + }; | ||
| 342 | + | ||
| 343 | + const requestPlay = async (fromAutoplay) => { | ||
| 344 | + const blocked = await openTrafficWarn(fromAutoplay); | ||
| 345 | + if (blocked) return; | ||
| 346 | + | ||
| 347 | + if (useNativePlayer.value) { | ||
| 348 | + tryNativePlay(); | ||
| 349 | + return; | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + if (player.value && !player.value.isDisposed()) { | ||
| 353 | + player.value.play().catch(console.warn); | ||
| 354 | + } | ||
| 355 | + }; | ||
| 356 | + | ||
| 357 | + const confirmTrafficWarn = () => { | ||
| 358 | + trafficWarnAcknowledged.value = true; | ||
| 359 | + closeTrafficWarn(); | ||
| 360 | + void requestPlay(trafficWarnDuringAutoplay); | ||
| 361 | + }; | ||
| 362 | + | ||
| 363 | + const cancelTrafficWarn = () => { | ||
| 364 | + closeTrafficWarn(); | ||
| 365 | + }; | ||
| 366 | + | ||
| 252 | // 4. 原生播放器逻辑 (iOS微信) | 367 | // 4. 原生播放器逻辑 (iOS微信) |
| 253 | const initNativePlayer = () => { | 368 | const initNativePlayer = () => { |
| 254 | const videoEl = nativeVideoRef.value; | 369 | const videoEl = nativeVideoRef.value; |
| ... | @@ -278,6 +393,28 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -278,6 +393,28 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 278 | }; | 393 | }; |
| 279 | 394 | ||
| 280 | const onPlay = () => { | 395 | const onPlay = () => { |
| 396 | + if (!trafficWarnAcknowledged.value) { | ||
| 397 | + if (!probeInfo.value.content_length && isOnCellular.value) { | ||
| 398 | + try { | ||
| 399 | + videoEl.pause(); | ||
| 400 | + } catch (e) { | ||
| 401 | + void e; | ||
| 402 | + } | ||
| 403 | + void requestPlay(false); | ||
| 404 | + return; | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + if (needTrafficWarn.value) { | ||
| 408 | + try { | ||
| 409 | + videoEl.pause(); | ||
| 410 | + } catch (e) { | ||
| 411 | + void e; | ||
| 412 | + } | ||
| 413 | + trafficWarnVisible.value = true; | ||
| 414 | + hideNetworkSpeed(); | ||
| 415 | + return; | ||
| 416 | + } | ||
| 417 | + } | ||
| 281 | hasEverPlayed.value = true; | 418 | hasEverPlayed.value = true; |
| 282 | hideNetworkSpeed(); | 419 | hideNetworkSpeed(); |
| 283 | }; | 420 | }; |
| ... | @@ -322,11 +459,11 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -322,11 +459,11 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 322 | }; | 459 | }; |
| 323 | 460 | ||
| 324 | if (props.autoplay) { | 461 | if (props.autoplay) { |
| 325 | - tryNativePlay(); | 462 | + void requestPlay(true); |
| 326 | if (typeof document !== "undefined") { | 463 | if (typeof document !== "undefined") { |
| 327 | document.addEventListener( | 464 | document.addEventListener( |
| 328 | "WeixinJSBridgeReady", | 465 | "WeixinJSBridgeReady", |
| 329 | - () => tryNativePlay(), | 466 | + () => void requestPlay(true), |
| 330 | { once: true } | 467 | { once: true } |
| 331 | ); | 468 | ); |
| 332 | } | 469 | } |
| ... | @@ -415,6 +552,20 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -415,6 +552,20 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 415 | }); | 552 | }); |
| 416 | 553 | ||
| 417 | player.value.on('play', () => { | 554 | player.value.on('play', () => { |
| 555 | + if (!trafficWarnAcknowledged.value) { | ||
| 556 | + if (!probeInfo.value.content_length && isOnCellular.value) { | ||
| 557 | + player.value.pause(); | ||
| 558 | + void requestPlay(false); | ||
| 559 | + return; | ||
| 560 | + } | ||
| 561 | + | ||
| 562 | + if (needTrafficWarn.value) { | ||
| 563 | + player.value.pause(); | ||
| 564 | + trafficWarnVisible.value = true; | ||
| 565 | + hideNetworkSpeed(); | ||
| 566 | + return; | ||
| 567 | + } | ||
| 568 | + } | ||
| 418 | hasEverPlayed.value = true; | 569 | hasEverPlayed.value = true; |
| 419 | hideNetworkSpeed(); | 570 | hideNetworkSpeed(); |
| 420 | }); | 571 | }); |
| ... | @@ -440,7 +591,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -440,7 +591,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 440 | }); | 591 | }); |
| 441 | 592 | ||
| 442 | if (props.autoplay) { | 593 | if (props.autoplay) { |
| 443 | - player.value.play().catch(console.warn); | 594 | + void requestPlay(true); |
| 444 | } | 595 | } |
| 445 | } | 596 | } |
| 446 | }; | 597 | }; |
| ... | @@ -455,6 +606,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -455,6 +606,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 455 | retryCount.value++; | 606 | retryCount.value++; |
| 456 | showErrorOverlay.value = false; | 607 | showErrorOverlay.value = false; |
| 457 | hideNetworkSpeed(); | 608 | hideNetworkSpeed(); |
| 609 | + closeTrafficWarn(); | ||
| 458 | 610 | ||
| 459 | if (useNativePlayer.value) { | 611 | if (useNativePlayer.value) { |
| 460 | const videoEl = nativeVideoRef.value; | 612 | const videoEl = nativeVideoRef.value; |
| ... | @@ -481,6 +633,8 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -481,6 +633,8 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 481 | showErrorOverlay.value = false; | 633 | showErrorOverlay.value = false; |
| 482 | hideNetworkSpeed(); | 634 | hideNetworkSpeed(); |
| 483 | hasEverPlayed.value = false; | 635 | hasEverPlayed.value = false; |
| 636 | + trafficWarnAcknowledged.value = false; | ||
| 637 | + closeTrafficWarn(); | ||
| 484 | void probeVideo(); | 638 | void probeVideo(); |
| 485 | 639 | ||
| 486 | // 如果是原生播放器且 URL 变化,需要手动处理 HLS (如果是非 iOS Safari 环境) | 640 | // 如果是原生播放器且 URL 变化,需要手动处理 HLS (如果是非 iOS Safari 环境) |
| ... | @@ -491,6 +645,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -491,6 +645,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 491 | }); | 645 | }); |
| 492 | 646 | ||
| 493 | onMounted(() => { | 647 | onMounted(() => { |
| 648 | + void detectNetworkKind(); | ||
| 494 | void probeVideo(); | 649 | void probeVideo(); |
| 495 | if (useNativePlayer.value) { | 650 | if (useNativePlayer.value) { |
| 496 | initNativePlayer(); | 651 | initNativePlayer(); |
| ... | @@ -514,6 +669,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -514,6 +669,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 514 | } | 669 | } |
| 515 | 670 | ||
| 516 | hideNetworkSpeed(); | 671 | hideNetworkSpeed(); |
| 672 | + closeTrafficWarn(); | ||
| 517 | if (videoRef.value?.$player) { | 673 | if (videoRef.value?.$player) { |
| 518 | videoRef.value.$player.dispose(); | 674 | videoRef.value.$player.dispose(); |
| 519 | } | 675 | } |
| ... | @@ -529,6 +685,13 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { | ... | @@ -529,6 +685,13 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { |
| 529 | errorMessage, | 685 | errorMessage, |
| 530 | showNetworkSpeedOverlay, | 686 | showNetworkSpeedOverlay, |
| 531 | networkSpeedText, | 687 | networkSpeedText, |
| 688 | + trafficWarnVisible, | ||
| 689 | + trafficFileSizeText, | ||
| 690 | + isOnWifi, | ||
| 691 | + isOnCellular, | ||
| 692 | + confirmTrafficWarn, | ||
| 693 | + cancelTrafficWarn, | ||
| 694 | + requestPlay, | ||
| 532 | retryLoad, | 695 | retryLoad, |
| 533 | handleVideoJsMounted, | 696 | handleVideoJsMounted, |
| 534 | tryNativePlay | 697 | tryNativePlay | ... | ... |
-
Please register or login to post a comment