134 lines
3.2 KiB
TypeScript
134 lines
3.2 KiB
TypeScript
// components/video-player/composables/useVideoProgress.ts
|
||
import { ref } from 'vue'
|
||
import { videoStorage } from '@/utils/videoStorage'
|
||
import { videoApi } from '@/api/modules/video'
|
||
import type { IVideoInfo } from '@/types/video'
|
||
|
||
/**
|
||
* 视频播放进度管理
|
||
*/
|
||
export function useVideoProgress() {
|
||
const currentTime = ref(0)
|
||
const isSaving = ref(false)
|
||
let saveTimer: any = null
|
||
|
||
/**
|
||
* 获取初始播放位置
|
||
* 合并本地和服务器的播放位置,取较大值
|
||
* 如果视频已经看完(播放位置 >= 总时长 - 5秒),则从头开始
|
||
*/
|
||
const getInitialPosition = (videoInfo: IVideoInfo): number => {
|
||
// 从服务器获取播放位置
|
||
const serverPosition = videoInfo.userCourseVideoPositionEntity?.position || 0
|
||
|
||
// 从本地存储获取播放位置
|
||
const localPosition = videoStorage.getVideoPosition(videoInfo.id) || 0
|
||
|
||
// 返回较大的值
|
||
// let position = Math.max(serverPosition, localPosition)
|
||
// 采用服务器记录的播放位置
|
||
let position = serverPosition
|
||
|
||
// 如果播放位置接近视频结尾(最后5秒内),则从头开始
|
||
const videoDuration = videoInfo.duration || 0
|
||
if (videoDuration > 0 && position >= videoDuration - 5) {
|
||
position = 0
|
||
console.log('Video already finished, reset to start')
|
||
}
|
||
|
||
console.log('Initial position:', {
|
||
server: serverPosition,
|
||
local: localPosition,
|
||
duration: videoDuration,
|
||
final: position
|
||
})
|
||
|
||
return position
|
||
}
|
||
|
||
/**
|
||
* 开始保存进度
|
||
* 每秒保存到本地
|
||
*/
|
||
const startSaving = (videoInfo: IVideoInfo) => {
|
||
// 清除之前的定时器
|
||
stopSaving()
|
||
|
||
// 每秒保存到本地
|
||
saveTimer = setInterval(() => {
|
||
if (currentTime.value > 0) {
|
||
videoStorage.saveVideoPosition(
|
||
videoInfo.id,
|
||
Math.floor(currentTime.value),
|
||
videoInfo
|
||
)
|
||
}
|
||
}, 1000)
|
||
}
|
||
|
||
/**
|
||
* 停止保存进度
|
||
*/
|
||
const stopSaving = () => {
|
||
if (saveTimer) {
|
||
clearInterval(saveTimer)
|
||
saveTimer = null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 保存进度到服务器
|
||
*/
|
||
const saveToServer = async (videoId: number, position: number) => {
|
||
if (isSaving.value) return
|
||
|
||
try {
|
||
isSaving.value = true
|
||
await videoApi.saveCoursePosition({
|
||
videoId,
|
||
position
|
||
})
|
||
console.log('Progress saved to server:', { videoId, position })
|
||
} catch (error) {
|
||
console.error('Failed to save progress to server:', error)
|
||
} finally {
|
||
isSaving.value = false
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 立即保存当前进度
|
||
*/
|
||
const saveNow = async (videoInfo: IVideoInfo) => {
|
||
if (currentTime.value > 0) {
|
||
// 保存到本地 注释掉: 不再保存到本地
|
||
// videoStorage.saveVideoPosition(
|
||
// videoInfo.id,
|
||
// Math.floor(currentTime.value),
|
||
// videoInfo
|
||
// )
|
||
|
||
// 保存到服务器
|
||
await saveToServer(videoInfo.id, Math.floor(currentTime.value))
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新当前播放时间
|
||
*/
|
||
const updateCurrentTime = (time: number) => {
|
||
currentTime.value = time
|
||
}
|
||
|
||
return {
|
||
currentTime,
|
||
isSaving,
|
||
getInitialPosition,
|
||
startSaving,
|
||
stopSaving,
|
||
saveToServer,
|
||
saveNow,
|
||
updateCurrentTime
|
||
}
|
||
}
|