deploy: auto commit repo-root changes 2026-07-03 19:33:14
This commit is contained in:
Generated
-6
@@ -24,7 +24,6 @@
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-5000320260310001",
|
||||
"@dcloudio/uni-webview-js": "0.0.3",
|
||||
"css-color-function": "1.3.3",
|
||||
"hls.js": "1.6.16",
|
||||
"lodash-es": "4.17.21",
|
||||
"pinia": "2.0.20",
|
||||
"uniapp-router-next": "1.2.7",
|
||||
@@ -13980,11 +13979,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hls.js": {
|
||||
"version": "1.6.16",
|
||||
"resolved": "https://registry.npmmirror.com/hls.js/-/hls.js-1.6.16.tgz",
|
||||
"integrity": "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA=="
|
||||
},
|
||||
"node_modules/html-encoding-sniffer": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-5000320260310001",
|
||||
"@dcloudio/uni-webview-js": "0.0.3",
|
||||
"css-color-function": "1.3.3",
|
||||
"hls.js": "1.6.16",
|
||||
"lodash-es": "4.17.21",
|
||||
"pinia": "2.0.20",
|
||||
"uniapp-router-next": "1.2.7",
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
@tap="openWorldCupLiveCard(live)">
|
||||
<view class="worldcup-live-card__player-wrap">
|
||||
<video :id="buildWorldCupLiveVideoId(live)" class="worldcup-live-card__player"
|
||||
:src="resolveWorldCupLiveVideoSrc(live)"
|
||||
:poster="live.home_icon || live.away_icon || ''" :muted="false" preload="none"
|
||||
:src="resolveWorldCupLivePlayUrl(live)"
|
||||
:poster="live.home_icon || live.away_icon || ''" :autoplay="true" :muted="true"
|
||||
:controls="!hideLiveCardControlsOnAndroid"
|
||||
:show-play-btn="!hideLiveCardControlsOnAndroid"
|
||||
:show-fullscreen-btn="!hideLiveCardControlsOnAndroid" object-fit="cover" />
|
||||
@@ -225,10 +225,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
// #ifdef H5
|
||||
import Hls from 'hls.js'
|
||||
// #endif
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import RankingNav from '../pages/worldcup/components/ranking/RankingNav.vue'
|
||||
import StandingsPanel from '../pages/worldcup/components/ranking/StandingsPanel.vue'
|
||||
import PlayerRankingPanel from '../pages/worldcup/components/ranking/PlayerRankingPanel.vue'
|
||||
@@ -287,12 +284,6 @@ const statusBarHeight = ref(0)
|
||||
const hideLiveCardControlsOnAndroid = ref(false)
|
||||
const liveCards = ref<WorldCupLiveCardItem[]>([])
|
||||
const liveCardsLoaded = ref(false)
|
||||
const activeWorldCupLiveKey = ref('')
|
||||
const h5NativeHlsSupported = ref(false)
|
||||
|
||||
// #ifdef H5
|
||||
let worldCupHlsPlayer: Hls | null = null
|
||||
// #endif
|
||||
|
||||
const scheduleData = ref<any>({
|
||||
current_round_name: '',
|
||||
@@ -435,18 +426,10 @@ const liveLineTitle = (live: WorldCupLiveCardItem) => {
|
||||
return normalizeLiveText(live.title) || '直播线路'
|
||||
}
|
||||
|
||||
const buildWorldCupLiveKey = (live: WorldCupLiveCardItem) => {
|
||||
return String(live.live_id || live.id || 0)
|
||||
}
|
||||
|
||||
const buildWorldCupLiveVideoId = (live: WorldCupLiveCardItem) => {
|
||||
return `worldcup-live-${buildWorldCupLiveKey(live)}`
|
||||
return `worldcup-live-${live.live_id || live.id || 0}`
|
||||
}
|
||||
|
||||
const isHlsLiveUrl = (url: string) => /\.m3u8(\?|$)/i.test(url)
|
||||
|
||||
const isFlvLiveUrl = (url: string) => /\.flv(\?|$)/i.test(url)
|
||||
|
||||
const resolveWorldCupLivePlayUrl = (live: WorldCupLiveCardItem) => {
|
||||
const urls: string[] = [
|
||||
live.play_url,
|
||||
@@ -469,19 +452,6 @@ const resolveWorldCupLivePlayUrl = (live: WorldCupLiveCardItem) => {
|
||||
return urls.find((url) => /\.(m3u8|mp4|flv)(\?|$)/i.test(url)) || urls[0] || ''
|
||||
}
|
||||
|
||||
const resolveWorldCupLiveVideoSrc = (live: WorldCupLiveCardItem) => {
|
||||
const url = resolveWorldCupLivePlayUrl(live)
|
||||
if (!url) return ''
|
||||
|
||||
// #ifdef H5
|
||||
if (activeWorldCupLiveKey.value !== buildWorldCupLiveKey(live)) return ''
|
||||
if (isFlvLiveUrl(url)) return ''
|
||||
if (isHlsLiveUrl(url) && !h5NativeHlsSupported.value) return ''
|
||||
// #endif
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
const liveStatusText = (live: WorldCupLiveCardItem) => {
|
||||
if ((live.status ?? 0) === 1) {
|
||||
return normalizeLiveText(live.current_minute) || '进行中'
|
||||
@@ -554,19 +524,6 @@ const activeBracketPairs = computed(() => {
|
||||
return pairs
|
||||
})
|
||||
|
||||
const detectH5NativeHlsSupported = () => {
|
||||
// #ifdef H5
|
||||
const video = document.createElement('video')
|
||||
return Boolean(
|
||||
video.canPlayType('application/vnd.apple.mpegurl') ||
|
||||
video.canPlayType('application/x-mpegURL')
|
||||
)
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
return false
|
||||
// #endif
|
||||
}
|
||||
|
||||
const initLayout = () => {
|
||||
const info = uni.getSystemInfoSync()
|
||||
hideLiveCardControlsOnAndroid.value = String(info.platform || '').toLowerCase() === 'android'
|
||||
@@ -575,7 +532,6 @@ const initLayout = () => {
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
statusBarHeight.value = 0
|
||||
h5NativeHlsSupported.value = detectH5NativeHlsSupported()
|
||||
// #endif
|
||||
}
|
||||
|
||||
@@ -673,167 +629,12 @@ const goMatchDetail = (match: any) => {
|
||||
uni.navigateTo({ url: `/pages/match_detail/match_detail?id=${id}` })
|
||||
}
|
||||
|
||||
const destroyWorldCupH5Player = () => {
|
||||
// #ifdef H5
|
||||
if (worldCupHlsPlayer) {
|
||||
worldCupHlsPlayer.destroy()
|
||||
worldCupHlsPlayer = null
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
const getH5WorldCupLiveVideoElement = (videoId: string): HTMLVideoElement | null => {
|
||||
// #ifdef H5
|
||||
const node = document.getElementById(videoId)
|
||||
if (!node) return null
|
||||
if (node instanceof HTMLVideoElement) return node
|
||||
return node.querySelector('video')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
return null
|
||||
// #endif
|
||||
}
|
||||
|
||||
const requestH5WorldCupLiveFullscreen = (video: HTMLVideoElement, videoId: string) => {
|
||||
// #ifdef H5
|
||||
try {
|
||||
const h5Video = video as HTMLVideoElement & {
|
||||
webkitEnterFullscreen?: () => void
|
||||
webkitRequestFullscreen?: () => Promise<void> | void
|
||||
msRequestFullscreen?: () => Promise<void> | void
|
||||
}
|
||||
|
||||
if (typeof h5Video.webkitEnterFullscreen === 'function') {
|
||||
h5Video.webkitEnterFullscreen()
|
||||
return
|
||||
}
|
||||
|
||||
const request = h5Video.requestFullscreen ||
|
||||
h5Video.webkitRequestFullscreen ||
|
||||
h5Video.msRequestFullscreen
|
||||
|
||||
if (typeof request === 'function') {
|
||||
const result = request.call(h5Video)
|
||||
if (result && typeof result.catch === 'function') {
|
||||
void result.catch(() => undefined)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
uni.createVideoContext(videoId)?.requestFullScreen?.({ direction: 90 })
|
||||
} catch {
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
const playH5WorldCupVideo = async (video: HTMLVideoElement) => {
|
||||
// #ifdef H5
|
||||
try {
|
||||
video.muted = false
|
||||
await video.play()
|
||||
} catch (error) {
|
||||
video.muted = true
|
||||
await video.play()
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
const loadH5WorldCupHlsSource = (video: HTMLVideoElement, url: string) => {
|
||||
// #ifdef H5
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (!Hls.isSupported()) {
|
||||
reject(new Error('HLS is not supported'))
|
||||
return
|
||||
}
|
||||
|
||||
destroyWorldCupH5Player()
|
||||
const hls = new Hls({
|
||||
enableWorker: true,
|
||||
lowLatencyMode: true,
|
||||
liveSyncDurationCount: 3,
|
||||
})
|
||||
worldCupHlsPlayer = hls
|
||||
|
||||
let settled = false
|
||||
const resolveOnce = () => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
resolve()
|
||||
}
|
||||
const rejectOnce = (error: Error) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
reject(error)
|
||||
}
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, resolveOnce)
|
||||
hls.on(Hls.Events.ERROR, (_event, data) => {
|
||||
if (data?.fatal) {
|
||||
rejectOnce(new Error(data.details || 'HLS fatal error'))
|
||||
}
|
||||
})
|
||||
hls.attachMedia(video)
|
||||
hls.loadSource(url)
|
||||
})
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
return Promise.resolve()
|
||||
// #endif
|
||||
}
|
||||
|
||||
const openH5WorldCupLiveCard = async (live: WorldCupLiveCardItem, playUrl: string) => {
|
||||
// #ifdef H5
|
||||
if (isFlvLiveUrl(playUrl)) {
|
||||
uni.showToast({ title: 'H5暂不支持FLV直播流', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
activeWorldCupLiveKey.value = buildWorldCupLiveKey(live)
|
||||
|
||||
const videoId = buildWorldCupLiveVideoId(live)
|
||||
const video = getH5WorldCupLiveVideoElement(videoId)
|
||||
if (!video) {
|
||||
uni.showToast({ title: '未找到直播播放器', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
requestH5WorldCupLiveFullscreen(video, videoId)
|
||||
|
||||
try {
|
||||
video.pause()
|
||||
if (isHlsLiveUrl(playUrl) && !h5NativeHlsSupported.value) {
|
||||
video.removeAttribute('src')
|
||||
video.load()
|
||||
await loadH5WorldCupHlsSource(video, playUrl)
|
||||
} else {
|
||||
destroyWorldCupH5Player()
|
||||
if (video.currentSrc !== playUrl && video.src !== playUrl) {
|
||||
video.src = playUrl
|
||||
video.load()
|
||||
}
|
||||
}
|
||||
|
||||
await playH5WorldCupVideo(video)
|
||||
} catch {
|
||||
destroyWorldCupH5Player()
|
||||
activeWorldCupLiveKey.value = ''
|
||||
uni.showToast({ title: '当前浏览器无法播放该直播流', icon: 'none' })
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
const openWorldCupLiveCard = (live: WorldCupLiveCardItem) => {
|
||||
const playUrl = resolveWorldCupLivePlayUrl(live)
|
||||
if (!playUrl) {
|
||||
if (!resolveWorldCupLivePlayUrl(live)) {
|
||||
uni.showToast({ title: '暂无直播链接', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
void openH5WorldCupLiveCard(live, playUrl)
|
||||
return
|
||||
// #endif
|
||||
|
||||
try {
|
||||
const videoContext = uni.createVideoContext(buildWorldCupLiveVideoId(live))
|
||||
videoContext?.requestFullScreen?.({
|
||||
@@ -969,10 +770,6 @@ const initViewState = async () => {
|
||||
}
|
||||
|
||||
watch(activeTab, (tab) => {
|
||||
if (tab !== 'live') {
|
||||
activeWorldCupLiveKey.value = ''
|
||||
destroyWorldCupH5Player()
|
||||
}
|
||||
ensureTabData(tab)
|
||||
}, { immediate: true })
|
||||
|
||||
@@ -991,10 +788,6 @@ watch(scheduleSort, () => {
|
||||
onMounted(() => {
|
||||
initViewState()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
destroyWorldCupH5Player()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user