Skip to content

Commit a8004e7

Browse files
author
Taois
committed
feat: 倍速定义
1 parent a462d44 commit a8004e7

File tree

3 files changed

+137
-7
lines changed

3 files changed

+137
-7
lines changed

dashboard/src/components/players/ArtVideoPlayer.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ import { Message } from '@arco-design/web-vue'
8181
import { IconClose } from '@arco-design/web-vue/es/icon'
8282
import Artplayer from 'artplayer'
8383
import Hls from 'hls.js'
84+
85+
// 配置自定义倍速选项
86+
Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2, 2.5, 3, 4, 5]
8487
import PlayerHeader from './PlayerHeader.vue'
8588
import SkipSettingsDialog from './SkipSettingsDialog.vue'
8689
import { useSkipSettings } from '@/composables/useSkipSettings'
@@ -161,7 +164,9 @@ const {
161164
closeSkipSettingsDialog,
162165
saveSkipSettings: saveSkipSettingsComposable,
163166
onUserSeekStart,
164-
onUserSeekEnd
167+
onUserSeekEnd,
168+
onFullscreenChangeStart,
169+
onFullscreenChangeEnd
165170
} = useSkipSettings({
166171
onSkipToNext: () => {
167172
if (autoNextEnabled.value && hasNextEpisode()) {
@@ -611,6 +616,14 @@ const initArtPlayer = async (url) => {
611616
// 监听全屏状态变化
612617
art.on('fullscreen', (isFullscreen) => {
613618
console.log('全屏状态变化:', isFullscreen)
619+
620+
// 标记全屏状态开始变化
621+
onFullscreenChangeStart()
622+
623+
// 500ms后标记全屏状态变化结束
624+
setTimeout(() => {
625+
onFullscreenChangeEnd()
626+
}, 500)
614627
})
615628
616629
art.on('video:error', (err) => {

dashboard/src/components/players/VideoPlayer.vue

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@
2626
您的浏览器不支持视频播放
2727
</video>
2828

29+
<!-- 倍速控制器 -->
30+
<div class="speed-control">
31+
<label for="speed-select">倍速:</label>
32+
<select
33+
id="speed-select"
34+
v-model="currentSpeed"
35+
@change="changePlaybackRate"
36+
class="speed-selector"
37+
>
38+
<option value="0.5">0.5x</option>
39+
<option value="0.75">0.75x</option>
40+
<option value="1">1x</option>
41+
<option value="1.25">1.25x</option>
42+
<option value="1.5">1.5x</option>
43+
<option value="2">2x</option>
44+
<option value="2.5">2.5x</option>
45+
<option value="3">3x</option>
46+
<option value="4">4x</option>
47+
<option value="5">5x</option>
48+
</select>
49+
</div>
50+
2951
<!-- 自动下一集倒计时弹窗 -->
3052
<div v-if="showAutoNextDialog" class="auto-next-dialog">
3153
<div class="auto-next-content">
@@ -113,6 +135,7 @@ const showAutoNextDialog = ref(false)
113135
const autoNextCountdown = ref(10)
114136
const countdownTimer = ref(null)
115137
const isProcessingAutoNext = ref(false) // 防止重复触发自动连播
138+
const currentSpeed = ref(1) // 当前播放倍速
116139
117140
// 检查是否有下一集
118141
const hasNextEpisode = () => {
@@ -208,6 +231,14 @@ const cancelAutoNext = () => {
208231
isProcessingAutoNext.value = false
209232
}
210233
234+
// 改变播放倍速
235+
const changePlaybackRate = () => {
236+
if (videoPlayer.value) {
237+
videoPlayer.value.playbackRate = parseFloat(currentSpeed.value)
238+
console.log('播放倍速已设置为:', currentSpeed.value)
239+
}
240+
}
241+
211242
// 链接类型判断函数
212243
const isDirectVideoLink = (url) => {
213244
if (!url) return false
@@ -748,6 +779,47 @@ onUnmounted(() => {
748779
background: #555;
749780
}
750781
782+
/* 倍速控制器样式 */
783+
.speed-control {
784+
position: absolute;
785+
top: 10px;
786+
right: 10px;
787+
background: rgba(0, 0, 0, 0.7);
788+
padding: 8px 12px;
789+
border-radius: 6px;
790+
display: flex;
791+
align-items: center;
792+
gap: 8px;
793+
z-index: 10;
794+
}
795+
796+
.speed-control label {
797+
color: white;
798+
font-size: 14px;
799+
font-weight: 500;
800+
}
801+
802+
.speed-selector {
803+
background: rgba(255, 255, 255, 0.9);
804+
border: 1px solid #ddd;
805+
border-radius: 4px;
806+
padding: 4px 8px;
807+
font-size: 14px;
808+
cursor: pointer;
809+
outline: none;
810+
transition: all 0.2s ease;
811+
}
812+
813+
.speed-selector:hover {
814+
background: white;
815+
border-color: #23ade5;
816+
}
817+
818+
.speed-selector:focus {
819+
border-color: #23ade5;
820+
box-shadow: 0 0 0 2px rgba(35, 173, 229, 0.2);
821+
}
822+
751823
752824
753825
/* 响应式设计 */

dashboard/src/composables/useSkipSettings.js

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ export function useSkipSettings(options = {}) {
2828
const skipOutroTimer = ref(null)
2929
const lastSkipTime = ref(0) // 记录上次跳过的时间戳,用于防抖
3030

31-
// 用户交互状态
32-
const userSeeking = ref(false) // 用户是否正在拖动进度条
33-
const lastUserSeekTime = ref(0) // 上次用户拖动的时间戳
31+
//// 用户交互状态
32+
const userSeeking = ref(false)
33+
const lastUserSeekTime = ref(0)
34+
35+
// 全屏状态跟踪
36+
const isFullscreenChanging = ref(false)
37+
const lastFullscreenChangeTime = ref(0) // 上次用户拖动的时间戳
3438

3539
// 计算属性
3640
const skipEnabled = computed(() => {
@@ -119,6 +123,18 @@ export function useSkipSettings(options = {}) {
119123
return
120124
}
121125

126+
// 检查是否正在全屏切换或刚刚切换过(2秒内)
127+
if (isFullscreenChanging.value || (lastFullscreenChangeTime.value > 0 && now - lastFullscreenChangeTime.value < 2000)) {
128+
console.log('正在全屏切换或刚刚切换过,跳过自动片头跳过')
129+
return
130+
}
131+
132+
// 检查是否正在全屏切换或刚刚切换过(2秒内)
133+
if (isFullscreenChanging.value || (lastFullscreenChangeTime.value > 0 && now - lastFullscreenChangeTime.value < 2000)) {
134+
console.log('正在全屏切换或刚刚切换过,跳过自动片头跳过')
135+
return
136+
}
137+
122138
// 立即跳过模式:如果当前时间很小(小于等于1秒)且在片头跳过范围内,立即跳过
123139
if (currentTime <= 1 && currentTime <= skipIntroSeconds.value) {
124140
console.log(`立即跳过片头:从 ${currentTime} 秒跳转到 ${skipIntroSeconds.value} 秒`)
@@ -163,6 +179,12 @@ export function useSkipSettings(options = {}) {
163179
return
164180
}
165181

182+
// 检查是否正在全屏切换或刚刚切换过(2秒内)
183+
if (isFullscreenChanging.value || (lastFullscreenChangeTime.value > 0 && now - lastFullscreenChangeTime.value < 2000)) {
184+
console.log('正在全屏切换或刚刚切换过,跳过自动片头跳过')
185+
return
186+
}
187+
166188
// 防抖:如果距离上次跳过不足1秒,则忽略(但如果是新视频,lastSkipTime为0,允许跳过)
167189
// 减少防抖时间,提高响应速度
168190
if (lastSkipTime.value > 0 && now - lastSkipTime.value < 1000) {
@@ -252,6 +274,10 @@ export function useSkipSettings(options = {}) {
252274
userSeeking.value = false
253275
lastUserSeekTime.value = 0
254276

277+
// 重置全屏状态
278+
isFullscreenChanging.value = false
279+
lastFullscreenChangeTime.value = 0
280+
255281
// 清除片尾跳过定时器(如果存在)
256282
if (skipOutroTimer.value) {
257283
clearTimeout(skipOutroTimer.value)
@@ -260,22 +286,39 @@ export function useSkipSettings(options = {}) {
260286
}
261287

262288
/**
263-
* 标记用户开始拖动进度条
289+
* 用户开始拖动进度条
264290
*/
265291
const onUserSeekStart = () => {
266292
userSeeking.value = true
267293
console.log('用户开始拖动进度条')
268294
}
269295

270296
/**
271-
* 标记用户结束拖动进度条
297+
* 用户结束拖动进度条
272298
*/
273299
const onUserSeekEnd = () => {
274300
userSeeking.value = false
275301
lastUserSeekTime.value = Date.now()
276302
console.log('用户结束拖动进度条')
277303
}
278304

305+
/**
306+
* 全屏状态开始变化
307+
*/
308+
const onFullscreenChangeStart = () => {
309+
isFullscreenChanging.value = true
310+
console.log('全屏状态开始变化')
311+
}
312+
313+
/**
314+
* 全屏状态变化结束
315+
*/
316+
const onFullscreenChangeEnd = () => {
317+
isFullscreenChanging.value = false
318+
lastFullscreenChangeTime.value = Date.now()
319+
console.log('全屏状态变化结束')
320+
}
321+
279322
/**
280323
* 初始化片头片尾设置
281324
*/
@@ -338,6 +381,8 @@ export function useSkipSettings(options = {}) {
338381
closeSkipSettingsDialog,
339382
cleanup,
340383
onUserSeekStart,
341-
onUserSeekEnd
384+
onUserSeekEnd,
385+
onFullscreenChangeStart,
386+
onFullscreenChangeEnd
342387
}
343388
}

0 commit comments

Comments
 (0)