From d157388680c09d61e85727e4a0917a288ff4291f Mon Sep 17 00:00:00 2001 From: Lunatic Date: Fri, 27 Feb 2026 14:33:19 +0800 Subject: [PATCH 1/7] Add per-chapter auto skip intro/outro for web player Per-book skip settings stored in browser localStorage. Checks each chapter's intro/outro zone during playback and automatically seeks past them, matching the behavior of the Android app implementation. --- .../components/app/MediaPlayerContainer.vue | 78 ++++++++++++++++++ .../components/modals/PlayerSettingsModal.vue | 80 ++++++++++++++++++- client/store/user.js | 3 +- 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 1a2b1d30a..474b5a598 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -308,6 +308,9 @@ export default { if (this.sleepTimerType === this.$constants.SleepTimerTypes.CHAPTER && this.sleepTimerSet) { this.checkChapterEnd() } + + // 检查章节intro/outro跳过 + this.checkAndSkipIntroOutro(time) }, setDuration(duration) { this.totalDuration = duration @@ -543,6 +546,81 @@ export default { this.playerHandler.resetPlayer() // Closes player without reporting to server this.$store.commit('setMediaPlaying', null) } + }, + + // 获取当前书籍的跳过设置 + getBookSkipSettings() { + if (!this.streamLibraryItem) return null + const bookSkipSettings = this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} + return bookSkipSettings[this.streamLibraryItem.id] || {} + }, + + // 检查并执行章节intro/outro跳过 + checkAndSkipIntroOutro(currentTime) { + const skipSettings = this.getBookSkipSettings() + if (!skipSettings) return + + const doSkipIntro = skipSettings.skipIntro && skipSettings.introDuration > 0 + const doSkipOutro = skipSettings.skipOutro && skipSettings.outroDuration > 0 + if (!doSkipIntro && !doSkipOutro) return + if (!this.isPlaying || !this.chapters.length) return + + // 防重入:正在跳过时等待到达目标位置后再解除 + if (this._isSkipping) { + if (this._skipTarget != null && currentTime >= this._skipTarget - 0.5) { + this._isSkipping = false + this._skipTarget = null + } + return + } + + const chapter = this.chapters.find((ch) => ch.start <= currentTime && currentTime < ch.end) + if (!chapter) return + + const introDuration = doSkipIntro ? skipSettings.introDuration : 0 + const outroDuration = doSkipOutro ? skipSettings.outroDuration : 0 + + const introEndTime = Math.min(chapter.start + introDuration, chapter.end) + const outroStartTime = Math.max(chapter.end - outroDuration, chapter.start) + + // 短章节:intro和outro区间重叠则不跳 + if (doSkipIntro && doSkipOutro && introEndTime > outroStartTime) return + + // 检查是否在intro区间 + if (doSkipIntro && currentTime < introEndTime) { + const target = introEndTime + 0.5 + this._isSkipping = true + this._skipTarget = target + this.seek(target) + return + } + + // 检查是否在outro区间 + if (doSkipOutro && currentTime >= outroStartTime) { + const chapterIndex = this.chapters.indexOf(chapter) + const nextChapter = this.chapters[chapterIndex + 1] + + if (nextChapter) { + // 有下一章:跳到下一章开头(如果同时开了skipIntro则跳过intro) + let target = nextChapter.start + if (doSkipIntro) { + const nextIntroEnd = Math.min(nextChapter.start + introDuration, nextChapter.end) + const nextOutroStart = Math.max(nextChapter.end - outroDuration, nextChapter.start) + // 确保下一章intro/outro不重叠 + if (nextIntroEnd <= nextOutroStart) { + target = nextIntroEnd + 0.5 + } + } + this._isSkipping = true + this._skipTarget = target + this.seek(target) + } else { + // 最后一章:跳到结尾,触发播放完成 + this._isSkipping = true + this._skipTarget = chapter.end + this.seek(chapter.end) + } + } } }, mounted() { diff --git a/client/components/modals/PlayerSettingsModal.vue b/client/components/modals/PlayerSettingsModal.vue index dfac28cfd..b7bbd1c6a 100644 --- a/client/components/modals/PlayerSettingsModal.vue +++ b/client/components/modals/PlayerSettingsModal.vue @@ -17,6 +17,29 @@
+ + +
+

本书跳过设置

+ +
+ +
+ 跳过开头 +
+ + +
+ +
+ +
+ 跳过结尾 +
+ + +
+
@@ -40,7 +63,14 @@ export default { jumpForwardAmount: 10, jumpBackwardAmount: 10, playbackRateIncrementDecrementValues: [0.1, 0.05], - playbackRateIncrementDecrement: 0.1 + playbackRateIncrementDecrement: 0.1, + + // 书籍跳过设置 + currentLibraryItemId: null, + skipIntro: false, + introDuration: 10, + skipOutro: false, + outroDuration: 10 } }, computed: { @@ -69,19 +99,67 @@ export default { this.playbackRateIncrementDecrement = val this.$store.dispatch('user/updateUserSettings', { playbackRateIncrementDecrement: val }) }, + + // 书籍跳过设置方法 + setSkipIntro() { + this.updateBookSkipSetting('skipIntro', this.skipIntro) + }, + setIntroDuration() { + this.introDuration = Math.max(0, Math.min(60, parseInt(this.introDuration) || 0)) + this.updateBookSkipSetting('introDuration', this.introDuration) + }, + setSkipOutro() { + this.updateBookSkipSetting('skipOutro', this.skipOutro) + }, + setOutroDuration() { + this.outroDuration = Math.max(0, Math.min(60, parseInt(this.outroDuration) || 0)) + this.updateBookSkipSetting('outroDuration', this.outroDuration) + }, + updateBookSkipSetting(key, value) { + if (!this.currentLibraryItemId) return + + const bookSkipSettings = { ...this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} } + if (!bookSkipSettings[this.currentLibraryItemId]) { + bookSkipSettings[this.currentLibraryItemId] = {} + } + bookSkipSettings[this.currentLibraryItemId][key] = value + this.$store.dispatch('user/updateUserSettings', { bookSkipSettings }) + }, settingsUpdated() { this.useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack') this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount') this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount') this.playbackRateIncrementDecrement = this.$store.getters['user/getUserSetting']('playbackRateIncrementDecrement') + + // 加载当前书籍的跳过设置 + this.loadBookSkipSettings() + }, + loadBookSkipSettings() { + // 获取当前播放的书籍ID + const mediaPlayerContainer = this.$root.$refs.mediaPlayerContainer || this.$parent.$refs.mediaPlayerContainer + if (mediaPlayerContainer && mediaPlayerContainer.streamLibraryItem) { + this.currentLibraryItemId = mediaPlayerContainer.streamLibraryItem.id + + const bookSkipSettings = this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} + const currentBookSettings = bookSkipSettings[this.currentLibraryItemId] || {} + + this.skipIntro = currentBookSettings.skipIntro || false + this.introDuration = currentBookSettings.introDuration || 10 + this.skipOutro = currentBookSettings.skipOutro || false + this.outroDuration = currentBookSettings.outroDuration || 10 + } else { + this.currentLibraryItemId = null + } } }, mounted() { this.settingsUpdated() this.$eventBus.$on('user-settings', this.settingsUpdated) + this.$eventBus.$on('playback-session-changed', this.loadBookSkipSettings) }, beforeDestroy() { this.$eventBus.$off('user-settings', this.settingsUpdated) + this.$eventBus.$off('playback-session-changed', this.loadBookSkipSettings) } } diff --git a/client/store/user.js b/client/store/user.js index 96e79d12f..e8bfb3da3 100644 --- a/client/store/user.js +++ b/client/store/user.js @@ -18,7 +18,8 @@ export const state = () => ({ authorSortBy: 'name', authorSortDesc: false, jumpForwardAmount: 10, - jumpBackwardAmount: 10 + jumpBackwardAmount: 10, + bookSkipSettings: {} // 书籍跳过配置 { [libraryItemId]: { skipIntro, introDuration, skipOutro, outroDuration } } } }) From 8a34eff1e927a45e963f41acb33a7420be84666f Mon Sep 17 00:00:00 2001 From: Lunatic Date: Fri, 27 Feb 2026 15:19:46 +0800 Subject: [PATCH 2/7] Refactor skip intro/outro to global settings instead of per-book Settings are now stored as top-level user settings in localStorage rather than nested under bookSkipSettings per libraryItemId. This makes the settings always accessible regardless of playback state. --- .../components/app/MediaPlayerContainer.vue | 15 +++-- .../components/modals/PlayerSettingsModal.vue | 60 ++++--------------- client/store/user.js | 5 +- 3 files changed, 26 insertions(+), 54 deletions(-) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 474b5a598..294a6907f 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -548,16 +548,19 @@ export default { } }, - // 获取当前书籍的跳过设置 - getBookSkipSettings() { - if (!this.streamLibraryItem) return null - const bookSkipSettings = this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} - return bookSkipSettings[this.streamLibraryItem.id] || {} + // 获取跳过设置 + getSkipSettings() { + return { + skipIntro: this.$store.getters['user/getUserSetting']('skipIntro'), + introDuration: this.$store.getters['user/getUserSetting']('introDuration'), + skipOutro: this.$store.getters['user/getUserSetting']('skipOutro'), + outroDuration: this.$store.getters['user/getUserSetting']('outroDuration') + } }, // 检查并执行章节intro/outro跳过 checkAndSkipIntroOutro(currentTime) { - const skipSettings = this.getBookSkipSettings() + const skipSettings = this.getSkipSettings() if (!skipSettings) return const doSkipIntro = skipSettings.skipIntro && skipSettings.introDuration > 0 diff --git a/client/components/modals/PlayerSettingsModal.vue b/client/components/modals/PlayerSettingsModal.vue index b7bbd1c6a..b116dd996 100644 --- a/client/components/modals/PlayerSettingsModal.vue +++ b/client/components/modals/PlayerSettingsModal.vue @@ -17,11 +17,10 @@
- - -
-

本书跳过设置

- + +
+

章节跳过设置

+
@@ -30,7 +29,7 @@
- +
@@ -64,9 +63,6 @@ export default { jumpBackwardAmount: 10, playbackRateIncrementDecrementValues: [0.1, 0.05], playbackRateIncrementDecrement: 0.1, - - // 书籍跳过设置 - currentLibraryItemId: null, skipIntro: false, introDuration: 10, skipOutro: false, @@ -99,67 +95,37 @@ export default { this.playbackRateIncrementDecrement = val this.$store.dispatch('user/updateUserSettings', { playbackRateIncrementDecrement: val }) }, - - // 书籍跳过设置方法 setSkipIntro() { - this.updateBookSkipSetting('skipIntro', this.skipIntro) + this.$store.dispatch('user/updateUserSettings', { skipIntro: this.skipIntro }) }, setIntroDuration() { this.introDuration = Math.max(0, Math.min(60, parseInt(this.introDuration) || 0)) - this.updateBookSkipSetting('introDuration', this.introDuration) + this.$store.dispatch('user/updateUserSettings', { introDuration: this.introDuration }) }, setSkipOutro() { - this.updateBookSkipSetting('skipOutro', this.skipOutro) + this.$store.dispatch('user/updateUserSettings', { skipOutro: this.skipOutro }) }, setOutroDuration() { this.outroDuration = Math.max(0, Math.min(60, parseInt(this.outroDuration) || 0)) - this.updateBookSkipSetting('outroDuration', this.outroDuration) - }, - updateBookSkipSetting(key, value) { - if (!this.currentLibraryItemId) return - - const bookSkipSettings = { ...this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} } - if (!bookSkipSettings[this.currentLibraryItemId]) { - bookSkipSettings[this.currentLibraryItemId] = {} - } - bookSkipSettings[this.currentLibraryItemId][key] = value - this.$store.dispatch('user/updateUserSettings', { bookSkipSettings }) + this.$store.dispatch('user/updateUserSettings', { outroDuration: this.outroDuration }) }, settingsUpdated() { this.useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack') this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount') this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount') this.playbackRateIncrementDecrement = this.$store.getters['user/getUserSetting']('playbackRateIncrementDecrement') - - // 加载当前书籍的跳过设置 - this.loadBookSkipSettings() - }, - loadBookSkipSettings() { - // 获取当前播放的书籍ID - const mediaPlayerContainer = this.$root.$refs.mediaPlayerContainer || this.$parent.$refs.mediaPlayerContainer - if (mediaPlayerContainer && mediaPlayerContainer.streamLibraryItem) { - this.currentLibraryItemId = mediaPlayerContainer.streamLibraryItem.id - - const bookSkipSettings = this.$store.getters['user/getUserSetting']('bookSkipSettings') || {} - const currentBookSettings = bookSkipSettings[this.currentLibraryItemId] || {} - - this.skipIntro = currentBookSettings.skipIntro || false - this.introDuration = currentBookSettings.introDuration || 10 - this.skipOutro = currentBookSettings.skipOutro || false - this.outroDuration = currentBookSettings.outroDuration || 10 - } else { - this.currentLibraryItemId = null - } + this.skipIntro = this.$store.getters['user/getUserSetting']('skipIntro') || false + this.introDuration = this.$store.getters['user/getUserSetting']('introDuration') || 10 + this.skipOutro = this.$store.getters['user/getUserSetting']('skipOutro') || false + this.outroDuration = this.$store.getters['user/getUserSetting']('outroDuration') || 10 } }, mounted() { this.settingsUpdated() this.$eventBus.$on('user-settings', this.settingsUpdated) - this.$eventBus.$on('playback-session-changed', this.loadBookSkipSettings) }, beforeDestroy() { this.$eventBus.$off('user-settings', this.settingsUpdated) - this.$eventBus.$off('playback-session-changed', this.loadBookSkipSettings) } } diff --git a/client/store/user.js b/client/store/user.js index e8bfb3da3..d702dd386 100644 --- a/client/store/user.js +++ b/client/store/user.js @@ -19,7 +19,10 @@ export const state = () => ({ authorSortDesc: false, jumpForwardAmount: 10, jumpBackwardAmount: 10, - bookSkipSettings: {} // 书籍跳过配置 { [libraryItemId]: { skipIntro, introDuration, skipOutro, outroDuration } } + skipIntro: false, + introDuration: 10, + skipOutro: false, + outroDuration: 10 } }) From 888852a12835f822f74545c7194853202600fcb6 Mon Sep 17 00:00:00 2001 From: Lunatic Date: Fri, 27 Feb 2026 16:06:16 +0800 Subject: [PATCH 3/7] Add i18n strings for chapter skip settings Replace hardcoded Chinese text in PlayerSettingsModal with i18n keys. Add HeaderChapterSkipSettings, LabelSkipChapterIntro, LabelSkipChapterOutro, LabelSeconds to en-us and zh-cn strings. --- client/components/modals/PlayerSettingsModal.vue | 10 +++++----- client/strings/en-us.json | 4 ++++ client/strings/zh-cn.json | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/client/components/modals/PlayerSettingsModal.vue b/client/components/modals/PlayerSettingsModal.vue index b116dd996..4d57435fc 100644 --- a/client/components/modals/PlayerSettingsModal.vue +++ b/client/components/modals/PlayerSettingsModal.vue @@ -19,24 +19,24 @@
-

章节跳过设置

+

{{ $strings.HeaderChapterSkipSettings }}

- 跳过开头 + {{ $strings.LabelSkipChapterIntro }}
- + {{ $strings.LabelSeconds }}
- 跳过结尾 + {{ $strings.LabelSkipChapterOutro }}
- + {{ $strings.LabelSeconds }}
diff --git a/client/strings/en-us.json b/client/strings/en-us.json index fb2bcb281..70e19565b 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -129,6 +129,7 @@ "HeaderBackups": "Backups", "HeaderBulkChapterModal": "Add Multiple Chapters", "HeaderChangePassword": "Change Password", + "HeaderChapterSkipSettings": "Chapter Skip Settings", "HeaderChapters": "Chapters", "HeaderChooseAFolder": "Choose a Folder", "HeaderCollection": "Collection", @@ -567,6 +568,7 @@ "LabelSearchTitleOrASIN": "Search Title or ASIN", "LabelSeason": "Season", "LabelSeasonNumber": "Season #{0}", + "LabelSeconds": "seconds", "LabelSelectAll": "Select all", "LabelSelectAllEpisodes": "Select all episodes", "LabelSelectEpisodesShowing": "Select {0} episodes showing", @@ -629,6 +631,8 @@ "LabelShowSeconds": "Show seconds", "LabelShowSubtitles": "Show Subtitles", "LabelSize": "Size", + "LabelSkipChapterIntro": "Skip chapter intro", + "LabelSkipChapterOutro": "Skip chapter outro", "LabelSleepTimer": "Sleep timer", "LabelSlug": "Slug", "LabelSortAscending": "Ascending", diff --git a/client/strings/zh-cn.json b/client/strings/zh-cn.json index 14c70cb10..4f245d9b9 100644 --- a/client/strings/zh-cn.json +++ b/client/strings/zh-cn.json @@ -129,6 +129,7 @@ "HeaderBackups": "备份", "HeaderBulkChapterModal": "添加多个章节", "HeaderChangePassword": "更改密码", + "HeaderChapterSkipSettings": "章节跳过设置", "HeaderChapters": "章节", "HeaderChooseAFolder": "选择文件夹", "HeaderCollection": "收藏", @@ -567,6 +568,7 @@ "LabelSearchTitleOrASIN": "搜索标题或 ASIN", "LabelSeason": "季", "LabelSeasonNumber": "第 {0} 季", + "LabelSeconds": "秒", "LabelSelectAll": "全选", "LabelSelectAllEpisodes": "选择所有剧集", "LabelSelectEpisodesShowing": "选择正在播放的 {0} 剧集", @@ -629,6 +631,8 @@ "LabelShowSeconds": "显示秒数", "LabelShowSubtitles": "显示标题", "LabelSize": "文件大小", + "LabelSkipChapterIntro": "跳过章节开头", + "LabelSkipChapterOutro": "跳过章节结尾", "LabelSleepTimer": "睡眠定时", "LabelSlug": "Slug", "LabelSortAscending": "升序", From ceeee97e63a9f808cb2ad34eb5d4dbec5d6e211a Mon Sep 17 00:00:00 2001 From: Lunatic Date: Fri, 27 Feb 2026 16:39:47 +0800 Subject: [PATCH 4/7] Suppress auto skip for 2s after manual seek Prevents intro/outro skip from immediately triggering when user uses jump back, prev chapter, or seeks manually into a skip zone. --- client/components/app/MediaPlayerContainer.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 294a6907f..42b2619a5 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -280,9 +280,11 @@ export default { this.playerHandler.playPause() }, jumpForward() { + this._manualSeekTime = Date.now() this.playerHandler.jumpForward() }, jumpBackward() { + this._manualSeekTime = Date.now() this.playerHandler.jumpBackward() }, setVolume(volume) { @@ -293,6 +295,7 @@ export default { this.playerHandler.setPlaybackRate(playbackRate) }, seek(time) { + this._manualSeekTime = Date.now() this.playerHandler.seek(time) }, playbackTimeUpdate(time) { @@ -568,6 +571,9 @@ export default { if (!doSkipIntro && !doSkipOutro) return if (!this.isPlaying || !this.chapters.length) return + // 用户手动seek后2秒内不触发跳过 + if (this._manualSeekTime && Date.now() - this._manualSeekTime < 2000) return + // 防重入:正在跳过时等待到达目标位置后再解除 if (this._isSkipping) { if (this._skipTarget != null && currentTime >= this._skipTarget - 0.5) { From 22cd48b39f1f8822a541d2050bebeca0aaa366ad Mon Sep 17 00:00:00 2001 From: Lunatic Date: Fri, 27 Feb 2026 18:57:39 +0800 Subject: [PATCH 5/7] Align skip i18n strings with app terminology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use title case in English and 片头/片尾 in Chinese to match the audiobookshelf-app translations. --- client/strings/en-us.json | 4 ++-- client/strings/zh-cn.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/strings/en-us.json b/client/strings/en-us.json index 70e19565b..f45bdfebc 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -631,8 +631,8 @@ "LabelShowSeconds": "Show seconds", "LabelShowSubtitles": "Show Subtitles", "LabelSize": "Size", - "LabelSkipChapterIntro": "Skip chapter intro", - "LabelSkipChapterOutro": "Skip chapter outro", + "LabelSkipChapterIntro": "Skip Chapter Intro", + "LabelSkipChapterOutro": "Skip Chapter Outro", "LabelSleepTimer": "Sleep timer", "LabelSlug": "Slug", "LabelSortAscending": "Ascending", diff --git a/client/strings/zh-cn.json b/client/strings/zh-cn.json index 4f245d9b9..83b8c2c66 100644 --- a/client/strings/zh-cn.json +++ b/client/strings/zh-cn.json @@ -631,8 +631,8 @@ "LabelShowSeconds": "显示秒数", "LabelShowSubtitles": "显示标题", "LabelSize": "文件大小", - "LabelSkipChapterIntro": "跳过章节开头", - "LabelSkipChapterOutro": "跳过章节结尾", + "LabelSkipChapterIntro": "跳过章节片头", + "LabelSkipChapterOutro": "跳过章节片尾", "LabelSleepTimer": "睡眠定时", "LabelSlug": "Slug", "LabelSortAscending": "升序", From a046c1a5f2c69302b0e0dd84a13532f455750761 Mon Sep 17 00:00:00 2001 From: Lunatic Date: Sat, 28 Feb 2026 09:17:11 +0800 Subject: [PATCH 6/7] i18n update title --- client/components/modals/PlayerSettingsModal.vue | 2 +- client/strings/en-us.json | 2 +- client/strings/zh-cn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/components/modals/PlayerSettingsModal.vue b/client/components/modals/PlayerSettingsModal.vue index 4d57435fc..4f7ca30f1 100644 --- a/client/components/modals/PlayerSettingsModal.vue +++ b/client/components/modals/PlayerSettingsModal.vue @@ -19,7 +19,7 @@
-

{{ $strings.HeaderChapterSkipSettings }}

+

{{ $strings.HeaderChapterIntroOutroSkipSettings }}

diff --git a/client/strings/en-us.json b/client/strings/en-us.json index f45bdfebc..a636d41b9 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -129,7 +129,7 @@ "HeaderBackups": "Backups", "HeaderBulkChapterModal": "Add Multiple Chapters", "HeaderChangePassword": "Change Password", - "HeaderChapterSkipSettings": "Chapter Skip Settings", + "HeaderChapterIntroOutroSkipSettings": "Intro/Outro Skip Settings", "HeaderChapters": "Chapters", "HeaderChooseAFolder": "Choose a Folder", "HeaderCollection": "Collection", diff --git a/client/strings/zh-cn.json b/client/strings/zh-cn.json index 83b8c2c66..4b32c0fb2 100644 --- a/client/strings/zh-cn.json +++ b/client/strings/zh-cn.json @@ -129,7 +129,7 @@ "HeaderBackups": "备份", "HeaderBulkChapterModal": "添加多个章节", "HeaderChangePassword": "更改密码", - "HeaderChapterSkipSettings": "章节跳过设置", + "HeaderChapterIntroOutroSkipSettings": "片头 / 片尾跳过设置", "HeaderChapters": "章节", "HeaderChooseAFolder": "选择文件夹", "HeaderCollection": "收藏", From 978128bf9922c95ee446809f2aeaf7270b238244 Mon Sep 17 00:00:00 2001 From: Lunatic Date: Sat, 28 Feb 2026 09:46:12 +0800 Subject: [PATCH 7/7] Translate the annotation from Chinese to English --- .../components/app/MediaPlayerContainer.vue | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 42b2619a5..3564a5670 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -312,7 +312,7 @@ export default { this.checkChapterEnd() } - // 检查章节intro/outro跳过 + // check for intro/outro and skip if needed this.checkAndSkipIntroOutro(time) }, setDuration(duration) { @@ -551,7 +551,7 @@ export default { } }, - // 获取跳过设置 + // get skip settings getSkipSettings() { return { skipIntro: this.$store.getters['user/getUserSetting']('skipIntro'), @@ -561,7 +561,7 @@ export default { } }, - // 检查并执行章节intro/outro跳过 + // check and skip intro/outro checkAndSkipIntroOutro(currentTime) { const skipSettings = this.getSkipSettings() if (!skipSettings) return @@ -571,10 +571,10 @@ export default { if (!doSkipIntro && !doSkipOutro) return if (!this.isPlaying || !this.chapters.length) return - // 用户手动seek后2秒内不触发跳过 + // The skip function is not triggered within 2 seconds after the user manually seeks if (this._manualSeekTime && Date.now() - this._manualSeekTime < 2000) return - // 防重入:正在跳过时等待到达目标位置后再解除 + // Reentry guard: When skipping, wait until reaching the target position before cancelling if (this._isSkipping) { if (this._skipTarget != null && currentTime >= this._skipTarget - 0.5) { this._isSkipping = false @@ -592,10 +592,10 @@ export default { const introEndTime = Math.min(chapter.start + introDuration, chapter.end) const outroStartTime = Math.max(chapter.end - outroDuration, chapter.start) - // 短章节:intro和outro区间重叠则不跳 + // Short chapter: If the intro and outro intervals overlap, do not skip if (doSkipIntro && doSkipOutro && introEndTime > outroStartTime) return - // 检查是否在intro区间 + // Check whether it is within the intro interval if (doSkipIntro && currentTime < introEndTime) { const target = introEndTime + 0.5 this._isSkipping = true @@ -604,18 +604,18 @@ export default { return } - // 检查是否在outro区间 + // check whether it is within the outro interval if (doSkipOutro && currentTime >= outroStartTime) { const chapterIndex = this.chapters.indexOf(chapter) const nextChapter = this.chapters[chapterIndex + 1] if (nextChapter) { - // 有下一章:跳到下一章开头(如果同时开了skipIntro则跳过intro) + // has next chapter: skip to next chapter start (if skipIntro is on, skip intro) let target = nextChapter.start if (doSkipIntro) { const nextIntroEnd = Math.min(nextChapter.start + introDuration, nextChapter.end) const nextOutroStart = Math.max(nextChapter.end - outroDuration, nextChapter.start) - // 确保下一章intro/outro不重叠 + // ensure that the next chapter intro/outro does not overlap if (nextIntroEnd <= nextOutroStart) { target = nextIntroEnd + 0.5 } @@ -624,7 +624,7 @@ export default { this._skipTarget = target this.seek(target) } else { - // 最后一章:跳到结尾,触发播放完成 + // last chapter: skip to end this._isSkipping = true this._skipTarget = chapter.end this.seek(chapter.end)