Date: Sat, 30 Aug 2025 23:41:56 +0200
Subject: [PATCH 07/35] add "remember its state in the watch session"
---
.../ft-shaka-video-player/ft-shaka-video-player.js | 13 +++++++++++++
.../player-components/SkipSilenceButton.js | 5 +++++
src/renderer/views/Watch/Watch.js | 5 +++++
src/renderer/views/Watch/Watch.vue | 2 ++
4 files changed, 25 insertions(+)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index f2a4f525318cb..dffc64d16e00d 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -145,6 +145,10 @@ export default defineComponent({
type: Number,
default: 1
},
+ skipSilenceEnabled: {
+ type: Boolean,
+ default: false
+ }
},
emits: [
'error',
@@ -156,6 +160,7 @@ export default defineComponent({
'playback-rate-updated',
'skip-to-next',
'skip-to-prev',
+ 'skip-silence-updated',
],
setup: function (props, { emit, expose }) {
const { locale, t } = useI18n()
@@ -2644,6 +2649,13 @@ export default defineComponent({
player.addEventListener('ratechange', () => {
emit('playback-rate-updated', player.getPlaybackRate())
})
+
+ if (store.getters.getSkipSilenceEnabled || props.skipSilenceEnabled) {
+ skipSilence()
+ events.dispatchEvent(new CustomEvent('setSkipSilence', {
+ detail: isSilenceSkipEnabled.value
+ }))
+ }
})
async function performFirstLoad() {
@@ -3061,6 +3073,7 @@ export default defineComponent({
showValueChange(t('SilenceSkip.Disable Silence Skip'))
isSilenceSkipEnabled.value = false
}
+ emit('skip-silence-updated', isSilenceSkipEnabled.value)
const video_ = video.value
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index a4a90e6548595..8dc444a190aa1 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -50,6 +50,11 @@ export class SkipSilenceButton extends shaka.ui.Element {
this.updateLocalisedStrings_()
})
+ this.eventManager.listen(events, 'setSkipSilence', (event) => {
+ this.skipSilenceEnabled_ = event.detail
+ this.updateLocalisedStrings_()
+ })
+
this.eventManager.listen(events, 'localeChanged', () => {
this.updateLocalisedStrings_()
})
diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js
index 3935550bf9a2b..c225d1e61d158 100644
--- a/src/renderer/views/Watch/Watch.js
+++ b/src/renderer/views/Watch/Watch.js
@@ -143,6 +143,7 @@ export default defineComponent({
/** @type {Date|null} */
streamingDataExpiryDate: null,
currentPlaybackRate: null,
+ skipSilenceEnabled: false
}
},
computed: {
@@ -339,6 +340,7 @@ export default defineComponent({
this.checkIfTimestamp()
this.currentPlaybackRate = this.$store.getters.getDefaultPlayback
+ this.skipSilenceEnabled = this.$store.getters.getSkipSilenceEnabled
},
mounted: function () {
this.onMountedDependOnLocalStateLoading()
@@ -1771,6 +1773,9 @@ export default defineComponent({
updatePlaybackRate(newRate) {
this.currentPlaybackRate = newRate
},
+ updateSkipSilence(newState) {
+ this.skipSilenceEnabled = newState
+ },
destroyPlayer: async function() {
const uiState = await this.$refs.player.destroyPlayer()
diff --git a/src/renderer/views/Watch/Watch.vue b/src/renderer/views/Watch/Watch.vue
index bbac535bb25f8..f485a5aea392e 100644
--- a/src/renderer/views/Watch/Watch.vue
+++ b/src/renderer/views/Watch/Watch.vue
@@ -40,6 +40,7 @@
:start-in-fullwindow="startNextVideoInFullwindow"
:start-in-pip="startNextVideoInPip"
:current-playback-rate="currentPlaybackRate"
+ :skip-silence-enabled="skipSilenceEnabled"
class="videoPlayer"
@error="handlePlayerError"
@loaded="handleVideoLoaded"
@@ -50,6 +51,7 @@
@playback-rate-updated="updatePlaybackRate"
@skip-to-next="handleSkipToNext"
@skip-to-prev="handleSkipToPrev"
+ @skip-silence-updated="updateSkipSilence"
/>
Date: Sat, 30 Aug 2025 23:44:03 +0200
Subject: [PATCH 08/35] add "a toggle in the Player settings called Enable
[name of the feature] by Default"
---
.../components/PlayerSettings/PlayerSettings.vue | 16 ++++++++++++++++
src/renderer/store/modules/settings.js | 1 +
static/locales/en-US.yaml | 1 +
3 files changed, 18 insertions(+)
diff --git a/src/renderer/components/PlayerSettings/PlayerSettings.vue b/src/renderer/components/PlayerSettings/PlayerSettings.vue
index 5fa3f77476b4d..821f607969785 100644
--- a/src/renderer/components/PlayerSettings/PlayerSettings.vue
+++ b/src/renderer/components/PlayerSettings/PlayerSettings.vue
@@ -73,6 +73,12 @@
:default-value="enterFullscreenOnDisplayRotate"
@change="updateEnterFullscreenOnDisplayRotate"
/>
+
@@ -383,6 +389,16 @@ function updateEnterFullscreenOnDisplayRotate(value) {
store.dispatch('updateEnterFullscreenOnDisplayRotate', value)
}
+/** @type {import('vue').ComputedRef} */
+const skipSilenceEnabled = computed(() => store.getters.getSkipSilenceEnabled)
+
+/**
+ * @param {boolean} value
+ */
+function updateSkipSilenceEnabled(value) {
+ store.dispatch('updateSkipSilenceEnabled', value)
+}
+
/** @type {import('vue').ComputedRef} */
const externalPlayer = computed(() => store.getters.getExternalPlayer)
diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js
index 502f53594d8af..f84cb24194c00 100644
--- a/src/renderer/store/modules/settings.js
+++ b/src/renderer/store/modules/settings.js
@@ -311,6 +311,7 @@ const state = {
uiScale: 100,
userPlaylistsSortBy: 'latest_played_first',
userHistorySortBy: 'latest_played_first',
+ skipSilenceEnabled: false,
}
const sideEffectHandlers = {
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 7597577510f21..4925434c653fb 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -454,6 +454,7 @@ Settings:
Skip by Scrolling Over Video Player: Skip by Scrolling Over Video Player
Display Play Button In Video Player: Display Play Button In Video Player
Enter Fullscreen on Display Rotate: Enter Fullscreen on Display Rotate
+ Skip Silence Enabled: Enable Skip Silence by Default
Next Video Interval: Autoplay Countdown Timer
Autoplay Interruption Timer: Autoplay Interruption Timer
Fast-Forward / Rewind Interval: Fast-Forward / Rewind Interval
From 2fa16b1fd83043eaa83bb2ea8958e6cf1367e45b Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Fri, 19 Sep 2025 20:58:55 +0200
Subject: [PATCH 09/35] remove duplicate value
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 938d0b3d5d811..6d5b3679d373a 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -826,7 +826,6 @@ export default defineComponent({
'captions',
'ft_audio_tracks',
'loop',
- 'ft_screenshot',
'picture_in_picture',
'ft_full_window',
'recenter_vr',
From 75ed66859990af8a71130513b1a6353a73a48439 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Fri, 19 Sep 2025 20:59:44 +0200
Subject: [PATCH 10/35] use new icon format
---
src/constants.js | 4 +++-
.../player-components/SkipSilenceButton.js | 9 +++------
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index 6346924633269..7b0b18f4ffb04 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -224,7 +224,9 @@ const PlayerIcons = {
PLAY_CIRCLE_FILLED: 'm426-330 195-125q14-9 14-25t-14-25L426-630q-15-10-30.5-1.5T380-605v250q0 18 15.5 26.5T426-330Zm54 250q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z',
SPATIAL_AUDIO_OFF_FILLED: 'M400-440q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM80-200v-32q0-33 17-62t47-44q51-26 115-44t141-18q77 0 141 18t115 44q30 15 47 44t17 62v32q0 33-23.5 56.5T640-120H160q-33 0-56.5-23.5T80-200Zm810-312q-8 0-15.5-3.5T862-524q-29-28-45-65t-16-78q0-41 16-77t45-65q5-5 12.5-8t15.5-3q17 0 28.5 11t11.5 28q0 8-3.5 16t-8.5 13q-17 17-27 39t-10 47q0 25 10 47t27 39q5 5 8.5 12.5T930-552q0 17-11.5 28.5T890-512ZM778-398q-8 0-15.5-3.5T750-410q-51-51-80-117.5T641-666q0-72 29-139t80-118q5-5 12.5-8t15.5-3q17 0 28.5 11.5T818-894q0 8-3 16t-9 13q-40 40-62.5 91T721-666q0 57 22.5 108.5T806-466q5 5 8.5 12.5T818-438q0 17-11.5 28.5T778-398Z',
TUNE_FILLED: 'M480-120q-17 0-28.5-11.5T440-160v-160q0-17 11.5-28.5T480-360q17 0 28.5 11.5T520-320v40h280q17 0 28.5 11.5T840-240q0 17-11.5 28.5T800-200H520v40q0 17-11.5 28.5T480-120Zm-320-80q-17 0-28.5-11.5T120-240q0-17 11.5-28.5T160-280h160q17 0 28.5 11.5T360-240q0 17-11.5 28.5T320-200H160Zm160-160q-17 0-28.5-11.5T280-400v-40H160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520h120v-40q0-17 11.5-28.5T320-600q17 0 28.5 11.5T360-560v160q0 17-11.5 28.5T320-360Zm160-80q-17 0-28.5-11.5T440-480q0-17 11.5-28.5T480-520h320q17 0 28.5 11.5T840-480q0 17-11.5 28.5T800-440H480Zm160-160q-17 0-28.5-11.5T600-640v-160q0-17 11.5-28.5T640-840q17 0 28.5 11.5T680-800v40h120q17 0 28.5 11.5T840-720q0 17-11.5 28.5T800-680H680v40q0 17-11.5 28.5T640-600Zm-480-80q-17 0-28.5-11.5T120-720q0-17 11.5-28.5T160-760h320q17 0 28.5 11.5T520-720q0 17-11.5 28.5T480-680H160Z',
- TV_DEFAULT: 'M160-200q-33 0-56.5-23.5T80-280v-480q0-33 23.5-56.5T160-840h640q33 0 56.5 23.5T880-760v480q0 33-23.5 56.5T800-200H640v40q0 17-11.5 28.5T600-120H360q-17 0-28.5-11.5T320-160v-40H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z'
+ TV_DEFAULT: 'M160-200q-33 0-56.5-23.5T80-280v-480q0-33 23.5-56.5T160-840h640q33 0 56.5 23.5T880-760v480q0 33-23.5 56.5T800-200H640v40q0 17-11.5 28.5T600-120H360q-17 0-28.5-11.5T320-160v-40H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z',
+ SKIP_SILENCE_DEFAULT: 'M360-840v-80h240v80H360Zm80 440h80v-240h-80v240Zm40 320q-74 0-139.5-28.5T226-186q-49-49-77.5-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q62 0 119 20t107 58l56-56 56 56-56 56q38 50 58 107t20 119q0 74-28.5 139.5T734-186q-49 49-114.5 77.5T480-80Zm0-80q116 0 198-82t82-198q0-116-82-198t-198-82q-116 0-198 82t-82 198q0 116 82 198t198 82Zm0-280Z',
+ SKIP_SILENCE_FILLED: 'M360-840v-80h240v80H360ZM480-80q-75 0-140.5-28.5T225-186q-49-49-77-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q63 0 120 21t104 59l58-58 56 56-56 58q36 47 57 104t21 120q0 74-28 139.5T735-186q-49 49-114.5 77.5T480-80Zm0-360Zm0-80h268q-18-62-61.5-109T584-700L480-520Zm-70 40 134-232q-59-15-121.5-2.5T306-660l104 180Zm-206 80h206L276-632q-42 47-62.5 106.5T204-400Zm172 220 104-180H212q18 62 61.5 109T376-180Zm40 12q66 17 128 1.5T654-220L550-400 416-168Zm268-80q44-48 63.5-107.5T756-480H550l134 232Z',
}
// Utils
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index 8dc444a190aa1..540dc72b63225 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -1,6 +1,7 @@
import shaka from 'shaka-player'
import i18n from '../../../i18n/index'
+import { PlayerIcons } from '../../../../constants'
export class SkipSilenceButton extends shaka.ui.Element {
/**
@@ -17,11 +18,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
this.button_.classList.add('skip-silence-button', 'shaka-tooltip')
/** @private */
- this.icon_ = document.createElement('i')
- this.icon_.classList.add('material-icons-round')
- this.icon_.textContent = 'timer'
-
- this.button_.appendChild(this.icon_)
+ this.icon_ = new shaka.ui.MaterialSVGIcon(this.button_, PlayerIcons.SKIP_SILENCE_DEFAULT)
const label = document.createElement('label')
label.classList.add('shaka-overflow-button-label', 'shaka-overflow-menu-only')
@@ -65,7 +62,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
/** @private */
updateLocalisedStrings_() {
this.nameSpan_.textContent = this.button_.ariaLabel = this.skipSilenceEnabled_ ? i18n.t('SilenceSkip.Enable Silence Skip') : i18n.t('SilenceSkip.Disable Silence Skip')
- this.icon_.textContent = this.skipSilenceEnabled_ ? 'shutter_speed' : 'timer'
+ this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SKIP_SILENCE_FILLED : PlayerIcons.SKIP_SILENCE_DEFAULT)
this.currentState_.textContent = this.localization.resolve(this.skipSilenceEnabled_ ? 'ON' : 'OFF')
}
}
From aa1dbdf2bc55df5557906c7ddeea8f0c7d422834 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 21:27:13 +0200
Subject: [PATCH 11/35] remove player icon
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 5a8554dea5eb7..c2c337cbd3ca2 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -845,7 +845,6 @@ export default defineComponent({
'picture_in_picture',
'ft_theatre_mode',
'ft_full_window',
- props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',
'fullscreen'
)
From 766bb9a43d66e3ed1e072ba15639ffe22805998b Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 21:37:34 +0200
Subject: [PATCH 12/35] move icon into overflow menu beneath loop
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index c2c337cbd3ca2..0c06406a000e4 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -827,6 +827,7 @@ export default defineComponent({
'captions',
'ft_audio_tracks',
'loop',
+ 'ft_skip_silence_toggle',
'picture_in_picture',
'ft_full_window',
'recenter_vr',
@@ -839,7 +840,6 @@ export default defineComponent({
} else {
uiConfig.controlPanelElements.push(
'ft_screenshot',
- 'ft_skip_silence_toggle',
'ft_autoplay_toggle',
'overflow_menu',
'picture_in_picture',
@@ -854,6 +854,7 @@ export default defineComponent({
'playback_rate',
props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',
'loop',
+ 'ft_skip_silence_toggle',
'recenter_vr',
'toggle_stereoscopic',
)
From 54cd5ec5df77107dc10990335edfda5a8c37bfa5 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:12:30 +0200
Subject: [PATCH 13/35] remove popup message
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 0c06406a000e4..2279658e12b24 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -3088,10 +3088,8 @@ export default defineComponent({
*/
function skipSilence() {
if (!isSilenceSkipEnabled.value) {
- showValueChange(t('SilenceSkip.Enable Silence Skip'))
isSilenceSkipEnabled.value = true
} else {
- showValueChange(t('SilenceSkip.Disable Silence Skip'))
isSilenceSkipEnabled.value = false
}
emit('skip-silence-updated', isSilenceSkipEnabled.value)
From 88d7593c4b178ace4a4446c27eff8481600ca60b Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:13:00 +0200
Subject: [PATCH 14/35] remove unused translation
---
static/locales/en-US.yaml | 2 --
1 file changed, 2 deletions(-)
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index bd5bff5c54f27..6d7406d7c3126 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -1219,5 +1219,3 @@ KeyboardShortcutPrompt:
SilenceSkip:
Skip Silence: Skip Silence
- Enable Silence Skip: Silence Skip enabled
- Disable Silence Skip: Silence Skip disabled
From 729e84e367f41a783e6c132237a9eaa7bdbd6e98 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:14:58 +0200
Subject: [PATCH 15/35] alter button for overflow menu
---
.../player-components/SkipSilenceButton.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index 540dc72b63225..30fbea8954d9c 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -21,7 +21,11 @@ export class SkipSilenceButton extends shaka.ui.Element {
this.icon_ = new shaka.ui.MaterialSVGIcon(this.button_, PlayerIcons.SKIP_SILENCE_DEFAULT)
const label = document.createElement('label')
- label.classList.add('shaka-overflow-button-label', 'shaka-overflow-menu-only')
+ label.classList.add(
+ 'shaka-overflow-button-label',
+ 'shaka-overflow-menu-only',
+ 'shaka-simple-overflow-button-label-inline'
+ )
/** @private */
this.nameSpan_ = document.createElement('span')
@@ -61,7 +65,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
/** @private */
updateLocalisedStrings_() {
- this.nameSpan_.textContent = this.button_.ariaLabel = this.skipSilenceEnabled_ ? i18n.t('SilenceSkip.Enable Silence Skip') : i18n.t('SilenceSkip.Disable Silence Skip')
+ this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('SilenceSkip.Skip Silence')
this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SKIP_SILENCE_FILLED : PlayerIcons.SKIP_SILENCE_DEFAULT)
this.currentState_.textContent = this.localization.resolve(this.skipSilenceEnabled_ ? 'ON' : 'OFF')
}
From efcdfcf409bedbd11943e75f90445fe0a9191855 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:35:35 +0200
Subject: [PATCH 16/35] cancelTrickPlay does not stop trickPlay anymore?
setting explicit to speed 1 instead
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 2279658e12b24..a847fe5b1dde1 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -3133,10 +3133,10 @@ export default defineComponent({
if (maxVolume <= averageVolume || maxVolume <= silencePercentage) {
player.trickPlay(2.5)
} else {
- player.cancelTrickPlay()
+ player.trickPlay(1)
}
} else {
- player.cancelTrickPlay()
+ player.trickPlay(1)
return
}
From 7c513cf43dc6c36c80189dd384ef478f5874ea26 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:39:30 +0200
Subject: [PATCH 17/35] bugfix, prevent fast forward when player is paused or
playback ended
---
.../ft-shaka-video-player/ft-shaka-video-player.js | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index a847fe5b1dde1..2e8f09170e47e 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -3121,16 +3121,15 @@ export default defineComponent({
return
}
- analyser.getByteTimeDomainData(amplitudeArray)
- const volumeValues = Array.from(amplitudeArray)
- const filteredVolumes = volumeValues.map(volume => volume - 128).filter(volume => volume !== 0).map(volume => Math.abs(volume))
- const maxVolume = filteredVolumes.length ? Math.max(...filteredVolumes) : 0
- const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
-
if (isSilenceSkipEnabled.value) {
+ analyser.getByteTimeDomainData(amplitudeArray)
+ const volumeValues = Array.from(amplitudeArray)
+ const filteredVolumes = volumeValues.map(volume => volume - 128).filter(volume => volume !== 0).map(volume => Math.abs(volume))
+ const maxVolume = filteredVolumes.length ? Math.max(...filteredVolumes) : 0
+ const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * 4 : 0
- if (maxVolume <= averageVolume || maxVolume <= silencePercentage) {
+ if ((maxVolume <= averageVolume || maxVolume <= silencePercentage) && !video.value.paused && !video.value.ended) {
player.trickPlay(2.5)
} else {
player.trickPlay(1)
From 22cdec158c4d844d13906315ee84e0905d34da69 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 22:43:31 +0200
Subject: [PATCH 18/35] Move toggle to the left side
---
.../components/PlayerSettings/PlayerSettings.vue | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/renderer/components/PlayerSettings/PlayerSettings.vue b/src/renderer/components/PlayerSettings/PlayerSettings.vue
index 821f607969785..e9be3b25d8902 100644
--- a/src/renderer/components/PlayerSettings/PlayerSettings.vue
+++ b/src/renderer/components/PlayerSettings/PlayerSettings.vue
@@ -40,6 +40,12 @@
:tooltip="t('Tooltips.Player Settings.Skip by Scrolling Over Video Player')"
@change="updateVideoSkipMouseScroll"
/>
+
-
From c65c8581a54127d8b7b7c74cc073009ca426b0e2 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 2 Oct 2025 23:16:22 +0200
Subject: [PATCH 19/35] bugfix, prevent skipSilence() speed multiplier if arrow
keys are used to skip forward/backward
---
.../ft-shaka-video-player.js | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 2e8f09170e47e..345ed9972a434 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -2194,6 +2194,8 @@ export default defineComponent({
return
}
+ const previousIsSilenceSkipEnabledState = isSilenceSkipEnabled.value
+
switch (event.key.toLowerCase()) {
case ' ':
case 'spacebar': // older browsers might return spacebar instead of a space character
@@ -2263,6 +2265,9 @@ export default defineComponent({
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_REWIND:
event.preventDefault()
+ if (previousIsSilenceSkipEnabledState) {
+ skipSilence()
+ }
if (canChapterJump(event, 'previous')) {
// Jump to the previous chapter
video_.currentTime = props.chapters[props.currentChapterIndex - 1].startSeconds
@@ -2271,9 +2276,15 @@ export default defineComponent({
// Rewind by the time-skip interval (in seconds)
seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), false, true)
}
+ if (previousIsSilenceSkipEnabledState) {
+ skipSilence()
+ }
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_FAST_FORWARD:
event.preventDefault()
+ if (previousIsSilenceSkipEnabledState) {
+ skipSilence()
+ }
if (canChapterJump(event, 'next')) {
// Jump to the next chapter
video_.currentTime = (props.chapters[props.currentChapterIndex + 1].startSeconds)
@@ -2282,6 +2293,9 @@ export default defineComponent({
// Fast-Forward by the time-skip interval (in seconds)
seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), false, true)
}
+ if (previousIsSilenceSkipEnabledState) {
+ skipSilence()
+ }
break
case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE:
// Toggle picture in picture
@@ -3129,7 +3143,7 @@ export default defineComponent({
const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * 4 : 0
- if ((maxVolume <= averageVolume || maxVolume <= silencePercentage) && !video.value.paused && !video.value.ended) {
+ if ((maxVolume <= averageVolume || maxVolume <= silencePercentage) && !video_.paused && !video_.ended) {
player.trickPlay(2.5)
} else {
player.trickPlay(1)
From 9d63f44baca7413ec82f988b420c3fbc8595fc85 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Wed, 8 Oct 2025 23:15:01 +0200
Subject: [PATCH 20/35] tune silence skip logic
---
src/constants.js | 9 +++
.../ft-shaka-video-player.js | 74 ++++++++++++-------
2 files changed, 58 insertions(+), 25 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index 631dfb7fa4aa2..193e000b8a41d 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -250,6 +250,14 @@ const MIXED_SEARCH_HISTORY_ENTRIES_DISPLAY_LIMIT = 4
// Displayed on the about page and used in the main.js file to only allow bitcoin URLs with this wallet address to be opened
const ABOUT_BITCOIN_ADDRESS = '1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS'
+const SilenceSkip = {
+ SILENCE_DETECTION_MULTIPLIER: 4, // Multiplier for silence detection. Higher = more sensitive
+ TRICKPLAY_FAST_FORWARD_SPEED: 3, // Trickplay speed when skipping silence. Higher = faster
+ TRICKPLAY_DEFAULT_SPEED: 1, // Trickplay speed when not skipping silence. 1 = normal
+ MIN_SILENCE_DURATION: 250, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
+ MIN_SOUND_DURATION: 5, // Min sound duration in ms. Higher to avoid false positives for short sounds.
+}
+
export {
IpcChannels,
DBActions,
@@ -257,6 +265,7 @@ export {
DefaultFolderKind,
KeyboardShortcuts,
PlayerIcons,
+ SilenceSkip,
MAIN_PROFILE_ID,
MOBILE_WIDTH_THRESHOLD,
PLAYLIST_HEIGHT_FORCE_LIST_THRESHOLD,
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 345ed9972a434..03f8bf450a00e 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -3,7 +3,7 @@ import shaka from 'shaka-player'
import { useI18n } from '../../composables/use-i18n-polyfill'
import store from '../../store/index'
-import { DefaultFolderKind, KeyboardShortcuts } from '../../../constants'
+import { DefaultFolderKind, KeyboardShortcuts, SilenceSkip } from '../../../constants'
import { AudioTrackSelection } from './player-components/AudioTrackSelection'
import { FullWindowButton } from './player-components/FullWindowButton'
import { LegacyQualitySelection } from './player-components/LegacyQualitySelection'
@@ -3083,22 +3083,17 @@ export default defineComponent({
/**
* Toggles and manages the silence skip functionality for the video player.
*
- * When silence skip is enabled, the function analyzes the audio stream of the
- * video to detect silent segments. If a silent segment is detected, the video
- * playback speed is increased to skip over the silence.
+ * When enabled, the function uses the Web Audio API to analyze the audio stream of the video element
+ * and detect silent segments. Silence detection is performed via an AnalyserNode connected in parallel
+ * to the audio output, allowing for volume analysis even when the output is muted during fast-forward.
*
- * The function uses the Web Audio API to create an AudioContext and connect it
- * to the video element's audio source. An AnalyserNode is used to obtain the
- * time-domain data of the audio signal, which is then processed to calculate
- * the maximum and average volume levels. Silence is determined by comparing
- * these levels, and if the conditions for silence are met, the player's
- * trickPlay method is invoked to increase the playback speed.
+ * The detection logic calculates the maximum and average amplitude of the audio signal. If a silent segment
+ * is detected and persists for a defined minimum duration, the video is fast-forwarded and the output is smoothly
+ * muted using a GainNode to avoid click artifacts. When non-silent audio is detected and persists for a minimum duration,
+ * the output is smoothly unmuted and playback speed returns to normal, with a additional delay to further reduce audio clicks.
*
- * If silence skip is disabled, the playback speed is reset to normal.
- *
- * The function initiates a loop using requestAnimationFrame to continuously
- * analyze the audio stream as long as the player exists and silence skip is
- * enabled.
+ * The function continuously analyzes the audio stream using requestAnimationFrame, adapting playback and muting in real time.
+ * All transitions for muting and unmuting use smooth ramping via setTargetAtTime for click-free audio..
*/
function skipSilence() {
if (!isSilenceSkipEnabled.value) {
@@ -3120,15 +3115,22 @@ export default defineComponent({
if (!video_.audioContext) {
video_.audioContext = audioContext
}
+ const gain = audioContext.createGain()
const analyser = audioContext.createAnalyser()
source.disconnect()
+ source.connect(gain)
source.connect(analyser)
- analyser.disconnect()
- analyser.connect(audioContext.destination)
+ gain.connect(audioContext.destination)
+
analyser.fftSize = 2048
const bufferLength = analyser.frequencyBinCount
const amplitudeArray = new Uint8Array(bufferLength)
+
let loopId = 0
+ let silenceStart = null
+ let soundStart = null
+ let isSkipping = false
+
const loop = () => {
if (!player) {
cancelAnimationFrame(loopId)
@@ -3138,18 +3140,40 @@ export default defineComponent({
if (isSilenceSkipEnabled.value) {
analyser.getByteTimeDomainData(amplitudeArray)
const volumeValues = Array.from(amplitudeArray)
- const filteredVolumes = volumeValues.map(volume => volume - 128).filter(volume => volume !== 0).map(volume => Math.abs(volume))
+ const filteredVolumes = volumeValues.map(v => v - 128).filter(v => v !== 0).map(Math.abs)
const maxVolume = filteredVolumes.length ? Math.max(...filteredVolumes) : 0
const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
- const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * 4 : 0
-
- if ((maxVolume <= averageVolume || maxVolume <= silencePercentage) && !video_.paused && !video_.ended) {
- player.trickPlay(2.5)
- } else {
- player.trickPlay(1)
+ const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * SilenceSkip.SILENCE_DETECTION_MULTIPLIER : 0
+ const isSilent = (maxVolume <= averageVolume || maxVolume <= silencePercentage)
+
+ const now = performance.now()
+
+ if (isSilent && !isSkipping && !video_.paused && !video_.ended && !video_.muted) {
+ if (!silenceStart) silenceStart = now
+ if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION) {
+ gain.gain.setTargetAtTime(0, audioContext.currentTime, 0.025)
+ player.trickPlay(SilenceSkip.TRICKPLAY_FAST_FORWARD_SPEED)
+ isSkipping = true
+ soundStart = null
+ }
+ } else if (!isSilent && isSkipping) {
+ if (!soundStart) soundStart = now
+ if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION) {
+ gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
+ setTimeout(() => {
+ player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ isSkipping = false
+ silenceStart = null
+ soundStart = null
+ }, 25)
+ }
+ } else if (!isSilent && !isSkipping) {
+ gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
+ silenceStart = null
+ soundStart = null
}
} else {
- player.trickPlay(1)
+ player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
return
}
From ecbc53068c057e92654b61497f6e576576ff2fb7 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:03:52 +0100
Subject: [PATCH 21/35] fix icon name
---
src/constants.js | 4 ++--
.../player-components/SkipSilenceButton.js | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index ae30521c729b3..073f50eb9ea46 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -225,8 +225,8 @@ const PlayerIcons = {
RECORD_VOICE_OVER_FILLED: 'M920-600q0 69-24.5 131.5T829-355q-12 14-30 15t-32-13q-13-13-12-31t12-33q30-38 46.5-85t16.5-98q0-51-16.5-97T767-781q-12-15-12.5-33t12.5-32q13-14 31.5-13.5T829-845q42 51 66.5 113.5T920-600Zm-182 0q0 32-10 61.5T700-484q-11 15-29.5 15.5T638-482q-13-13-13.5-31.5T633-549q6-11 9.5-24t3.5-27q0-14-3.5-27t-9.5-25q-9-17-8.5-35t13.5-31q14-14 32.5-13.5T700-716q18 25 28 54.5t10 61.5ZM360-440q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM40-200v-32q0-33 17-62t47-44q51-26 115-44t141-18q77 0 141 18t115 44q30 15 47 44t17 62v32q0 33-23.5 56.5T600-120H120q-33 0-56.5-23.5T40-200Z',
TUNE_FILLED: 'M480-120q-17 0-28.5-11.5T440-160v-160q0-17 11.5-28.5T480-360q17 0 28.5 11.5T520-320v40h280q17 0 28.5 11.5T840-240q0 17-11.5 28.5T800-200H520v40q0 17-11.5 28.5T480-120Zm-320-80q-17 0-28.5-11.5T120-240q0-17 11.5-28.5T160-280h160q17 0 28.5 11.5T360-240q0 17-11.5 28.5T320-200H160Zm160-160q-17 0-28.5-11.5T280-400v-40H160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520h120v-40q0-17 11.5-28.5T320-600q17 0 28.5 11.5T360-560v160q0 17-11.5 28.5T320-360Zm160-80q-17 0-28.5-11.5T440-480q0-17 11.5-28.5T480-520h320q17 0 28.5 11.5T840-480q0 17-11.5 28.5T800-440H480Zm160-160q-17 0-28.5-11.5T600-640v-160q0-17 11.5-28.5T640-840q17 0 28.5 11.5T680-800v40h120q17 0 28.5 11.5T840-720q0 17-11.5 28.5T800-680H680v40q0 17-11.5 28.5T640-600Zm-480-80q-17 0-28.5-11.5T120-720q0-17 11.5-28.5T160-760h320q17 0 28.5 11.5T520-720q0 17-11.5 28.5T480-680H160Z',
RECTANGLE_DEFAULT: 'M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z',
- SKIP_SILENCE_DEFAULT: 'M360-840v-80h240v80H360Zm80 440h80v-240h-80v240Zm40 320q-74 0-139.5-28.5T226-186q-49-49-77.5-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q62 0 119 20t107 58l56-56 56 56-56 56q38 50 58 107t20 119q0 74-28.5 139.5T734-186q-49 49-114.5 77.5T480-80Zm0-80q116 0 198-82t82-198q0-116-82-198t-198-82q-116 0-198 82t-82 198q0 116 82 198t198 82Zm0-280Z',
- SKIP_SILENCE_FILLED: 'M360-840v-80h240v80H360ZM480-80q-75 0-140.5-28.5T225-186q-49-49-77-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q63 0 120 21t104 59l58-58 56 56-56 58q36 47 57 104t21 120q0 74-28 139.5T735-186q-49 49-114.5 77.5T480-80Zm0-360Zm0-80h268q-18-62-61.5-109T584-700L480-520Zm-70 40 134-232q-59-15-121.5-2.5T306-660l104 180Zm-206 80h206L276-632q-42 47-62.5 106.5T204-400Zm172 220 104-180H212q18 62 61.5 109T376-180Zm40 12q66 17 128 1.5T654-220L550-400 416-168Zm268-80q44-48 63.5-107.5T756-480H550l134 232Z',
+ TIMER_DEFAULT: 'M360-840v-80h240v80H360Zm80 440h80v-240h-80v240Zm40 320q-74 0-139.5-28.5T226-186q-49-49-77.5-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q62 0 119 20t107 58l56-56 56 56-56 56q38 50 58 107t20 119q0 74-28.5 139.5T734-186q-49 49-114.5 77.5T480-80Zm0-80q116 0 198-82t82-198q0-116-82-198t-198-82q-116 0-198 82t-82 198q0 116 82 198t198 82Zm0-280Z',
+ SHUTTER_SPEED_DEFAULT: 'M360-840v-80h240v80H360ZM480-80q-75 0-140.5-28.5T225-186q-49-49-77-114.5T120-440q0-74 28.5-139.5T226-694q49-49 114.5-77.5T480-800q63 0 120 21t104 59l58-58 56 56-56 58q36 47 57 104t21 120q0 74-28 139.5T735-186q-49 49-114.5 77.5T480-80Zm0-360Zm0-80h268q-18-62-61.5-109T584-700L480-520Zm-70 40 134-232q-59-15-121.5-2.5T306-660l104 180Zm-206 80h206L276-632q-42 47-62.5 106.5T204-400Zm172 220 104-180H212q18 62 61.5 109T376-180Zm40 12q66 17 128 1.5T654-220L550-400 416-168Zm268-80q44-48 63.5-107.5T756-480H550l134 232Z',
}
// Utils
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index 30fbea8954d9c..2fdac07e2dd2f 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -18,7 +18,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
this.button_.classList.add('skip-silence-button', 'shaka-tooltip')
/** @private */
- this.icon_ = new shaka.ui.MaterialSVGIcon(this.button_, PlayerIcons.SKIP_SILENCE_DEFAULT)
+ this.icon_ = new shaka.ui.MaterialSVGIcon(this.button_, PlayerIcons.TIMER_DEFAULT)
const label = document.createElement('label')
label.classList.add(
@@ -65,8 +65,8 @@ export class SkipSilenceButton extends shaka.ui.Element {
/** @private */
updateLocalisedStrings_() {
- this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('SilenceSkip.Skip Silence')
- this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SKIP_SILENCE_FILLED : PlayerIcons.SKIP_SILENCE_DEFAULT)
+ this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('Video.Player.SilenceSkip.Skip Silence')
+ this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SHUTTER_SPEED_DEFAULT : PlayerIcons.TIMER_DEFAULT)
this.currentState_.textContent = this.localization.resolve(this.skipSilenceEnabled_ ? 'ON' : 'OFF')
}
}
From 338cd093fa00a455e04f59c838d1c8816ccdc592 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:04:42 +0100
Subject: [PATCH 22/35] movie into player section
---
static/locales/en-US.yaml | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 9f751dcbc6415..126a380e01c57 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -945,6 +945,8 @@ Video:
You appear to be offline: You appear to be offline.
Playback will resume automatically when your connection comes back: Playback will resume automatically when your connection comes back.
Skipped segment: 'Skipped {segmentCategory} segment'
+ SilenceSkip:
+ Skip Silence: Skip Silence
#& Playlists
Playlist:
#& About
@@ -1216,6 +1218,3 @@ KeyboardShortcutPrompt:
End: Seek to the end of the video
Skip to Next Video: Skip to the next video in a playlist or next recommended video
Skip to Previous Video: Skip to the previous video in a playlist
-
-SilenceSkip:
- Skip Silence: Skip Silence
From c291226dbcfdf05c31b10cac966fd4192682433a Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:05:52 +0100
Subject: [PATCH 23/35] remove from "The settings below have side effects"
section
---
src/renderer/store/modules/settings.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js
index f7d02fecf1705..14541ca52e600 100644
--- a/src/renderer/store/modules/settings.js
+++ b/src/renderer/store/modules/settings.js
@@ -305,6 +305,7 @@ const state = {
quickBookmarkTargetPlaylistId: 'favorites',
generalAutoLoadMorePaginatedItemsEnabled: false,
hideToTrayOnMinimize: false,
+ skipSilenceEnabled: false,
// The settings below have side effects
currentLocale: 'system',
@@ -313,7 +314,6 @@ const state = {
uiScale: 100,
userPlaylistsSortBy: 'latest_played_first',
userHistorySortBy: 'latest_played_first',
- skipSilenceEnabled: false,
}
const sideEffectHandlers = {
From c32e4a7fafa4bd58ea56d965a0b4e030f4f545bc Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:09:12 +0100
Subject: [PATCH 24/35] move into video event region
---
.../ft-shaka-video-player.js | 204 +++++++++---------
1 file changed, 100 insertions(+), 104 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 039f33602a981..ea7a5829d8ee9 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -1216,6 +1216,105 @@ export default defineComponent({
}
}
+ /**
+ * Toggles and manages the silence skip functionality for the video player.
+ *
+ * When enabled, the function uses the Web Audio API to analyze the audio stream of the video element
+ * and detect silent segments. Silence detection is performed via an AnalyserNode connected in parallel
+ * to the audio output, allowing for volume analysis even when the output is muted during fast-forward.
+ *
+ * The detection logic calculates the maximum and average amplitude of the audio signal. If a silent segment
+ * is detected and persists for a defined minimum duration, the video is fast-forwarded and the output is smoothly
+ * muted using a GainNode to avoid click artifacts. When non-silent audio is detected and persists for a minimum duration,
+ * the output is smoothly unmuted and playback speed returns to normal, with a additional delay to further reduce audio clicks.
+ *
+ * The function continuously analyzes the audio stream using requestAnimationFrame, adapting playback and muting in real time.
+ * All transitions for muting and unmuting use smooth ramping via setTargetAtTime for click-free audio..
+ */
+ function skipSilence() {
+ isSilenceSkipEnabled.value = !isSilenceSkipEnabled.value
+
+ const video_ = video.value
+
+ if (video_ && player) {
+ const audioContext = video_.audioContext ?? new AudioContext()
+ let source = video_.audioSource
+ if (!source) {
+ source = audioContext.createMediaElementSource(video_)
+ video_.audioSource = source
+ }
+ if (!video_.audioContext) {
+ video_.audioContext = audioContext
+ }
+ const gain = audioContext.createGain()
+ const analyser = audioContext.createAnalyser()
+ source.disconnect()
+ source.connect(gain)
+ source.connect(analyser)
+ gain.connect(audioContext.destination)
+
+ analyser.fftSize = 2048
+ const bufferLength = analyser.frequencyBinCount
+ const amplitudeArray = new Uint8Array(bufferLength)
+
+ let loopId = 0
+ let silenceStart = null
+ let soundStart = null
+ let isSkipping = false
+
+ const loop = () => {
+ if (!player) {
+ cancelAnimationFrame(loopId)
+ return
+ }
+
+ if (isSilenceSkipEnabled.value) {
+ analyser.getByteTimeDomainData(amplitudeArray)
+ const volumeValues = Array.from(amplitudeArray)
+ const filteredVolumes = volumeValues.map(v => v - 128).filter(v => v !== 0).map(Math.abs)
+ const maxVolume = filteredVolumes.length ? Math.max(...filteredVolumes) : 0
+ const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
+ const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * SilenceSkip.SILENCE_DETECTION_MULTIPLIER : 0
+ const isSilent = (maxVolume <= averageVolume || maxVolume <= silencePercentage)
+
+ const now = performance.now()
+
+ if (isSilent && !isSkipping && !video_.paused && !video_.ended && !video_.muted) {
+ if (!silenceStart) silenceStart = now
+ if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION) {
+ gain.gain.setTargetAtTime(0, audioContext.currentTime, 0.025)
+ player.trickPlay(SilenceSkip.TRICKPLAY_FAST_FORWARD_SPEED)
+ isSkipping = true
+ soundStart = null
+ }
+ } else if (!isSilent && isSkipping) {
+ if (!soundStart) soundStart = now
+ if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION) {
+ gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
+ setTimeout(() => {
+ player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ isSkipping = false
+ silenceStart = null
+ soundStart = null
+ }, 25)
+ }
+ } else if (!isSilent && !isSkipping) {
+ gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
+ silenceStart = null
+ soundStart = null
+ }
+ } else {
+ player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ return
+ }
+
+ loopId = requestAnimationFrame(loop)
+ }
+
+ loop()
+ }
+ }
+
// #endregion video event handlers
// #region request/response filters
@@ -1723,6 +1822,7 @@ export default defineComponent({
function registerSkipSilenceToggle() {
events.addEventListener('toggleSkipSilence', () => {
+ emit('skip-silence-updated', !isSilenceSkipEnabled.value)
skipSilence()
})
@@ -3072,110 +3172,6 @@ export default defineComponent({
return uiState
}
- /**
- * Toggles and manages the silence skip functionality for the video player.
- *
- * When enabled, the function uses the Web Audio API to analyze the audio stream of the video element
- * and detect silent segments. Silence detection is performed via an AnalyserNode connected in parallel
- * to the audio output, allowing for volume analysis even when the output is muted during fast-forward.
- *
- * The detection logic calculates the maximum and average amplitude of the audio signal. If a silent segment
- * is detected and persists for a defined minimum duration, the video is fast-forwarded and the output is smoothly
- * muted using a GainNode to avoid click artifacts. When non-silent audio is detected and persists for a minimum duration,
- * the output is smoothly unmuted and playback speed returns to normal, with a additional delay to further reduce audio clicks.
- *
- * The function continuously analyzes the audio stream using requestAnimationFrame, adapting playback and muting in real time.
- * All transitions for muting and unmuting use smooth ramping via setTargetAtTime for click-free audio..
- */
- function skipSilence() {
- if (!isSilenceSkipEnabled.value) {
- isSilenceSkipEnabled.value = true
- } else {
- isSilenceSkipEnabled.value = false
- }
- emit('skip-silence-updated', isSilenceSkipEnabled.value)
-
- const video_ = video.value
-
- if (video_ && player) {
- const audioContext = video_.audioContext ?? new AudioContext()
- let source = video_.audioSource
- if (!source) {
- source = audioContext.createMediaElementSource(video_)
- video_.audioSource = source
- }
- if (!video_.audioContext) {
- video_.audioContext = audioContext
- }
- const gain = audioContext.createGain()
- const analyser = audioContext.createAnalyser()
- source.disconnect()
- source.connect(gain)
- source.connect(analyser)
- gain.connect(audioContext.destination)
-
- analyser.fftSize = 2048
- const bufferLength = analyser.frequencyBinCount
- const amplitudeArray = new Uint8Array(bufferLength)
-
- let loopId = 0
- let silenceStart = null
- let soundStart = null
- let isSkipping = false
-
- const loop = () => {
- if (!player) {
- cancelAnimationFrame(loopId)
- return
- }
-
- if (isSilenceSkipEnabled.value) {
- analyser.getByteTimeDomainData(amplitudeArray)
- const volumeValues = Array.from(amplitudeArray)
- const filteredVolumes = volumeValues.map(v => v - 128).filter(v => v !== 0).map(Math.abs)
- const maxVolume = filteredVolumes.length ? Math.max(...filteredVolumes) : 0
- const averageVolume = filteredVolumes.length ? filteredVolumes.reduce((a, b) => a + b, 0) / filteredVolumes.length : 0
- const silencePercentage = !isNaN(maxVolume) && !isNaN(averageVolume) ? (averageVolume / maxVolume) * SilenceSkip.SILENCE_DETECTION_MULTIPLIER : 0
- const isSilent = (maxVolume <= averageVolume || maxVolume <= silencePercentage)
-
- const now = performance.now()
-
- if (isSilent && !isSkipping && !video_.paused && !video_.ended && !video_.muted) {
- if (!silenceStart) silenceStart = now
- if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION) {
- gain.gain.setTargetAtTime(0, audioContext.currentTime, 0.025)
- player.trickPlay(SilenceSkip.TRICKPLAY_FAST_FORWARD_SPEED)
- isSkipping = true
- soundStart = null
- }
- } else if (!isSilent && isSkipping) {
- if (!soundStart) soundStart = now
- if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION) {
- gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
- setTimeout(() => {
- player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
- isSkipping = false
- silenceStart = null
- soundStart = null
- }, 25)
- }
- } else if (!isSilent && !isSkipping) {
- gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
- silenceStart = null
- soundStart = null
- }
- } else {
- player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
- return
- }
-
- loopId = requestAnimationFrame(loop)
- }
-
- loop()
- }
- }
-
expose({
hasLoaded,
From 9bdcaf2249f84d87967e820ab2d473a2cc95512d Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:11:19 +0100
Subject: [PATCH 25/35] remove duplicate entry
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index ea7a5829d8ee9..33b9040fd0bfd 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -820,7 +820,6 @@ export default defineComponent({
if (onlyUseOverFlowMenu.value) {
uiConfig.overflowMenuButtons = [
'ft_screenshot',
- 'ft_skip_silence_toggle',
'ft_autoplay_toggle',
props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',
'playback_rate',
From a9ee002276429268f57732f67bfc7a71111f12f1 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:12:15 +0100
Subject: [PATCH 26/35] fix watch session
---
.../ft-shaka-video-player/ft-shaka-video-player.js | 2 +-
src/renderer/views/Watch/Watch.js | 6 +++---
src/renderer/views/Watch/Watch.vue | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 33b9040fd0bfd..dd1dc12400eb3 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -2773,7 +2773,7 @@ export default defineComponent({
emit('playback-rate-updated', player.getPlaybackRate())
})
- if (store.getters.getSkipSilenceEnabled || props.skipSilenceEnabled) {
+ if (props.skipSilenceEnabled) {
skipSilence()
events.dispatchEvent(new CustomEvent('setSkipSilence', {
detail: isSilenceSkipEnabled.value
diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js
index 1ffa719123a3e..3bf6afdd49ea4 100644
--- a/src/renderer/views/Watch/Watch.js
+++ b/src/renderer/views/Watch/Watch.js
@@ -143,7 +143,7 @@ export default defineComponent({
/** @type {Date|null} */
streamingDataExpiryDate: null,
currentPlaybackRate: null,
- skipSilenceEnabled: false
+ startNextVideoWithSkipSilenceEnabled: false
}
},
computed: {
@@ -340,7 +340,7 @@ export default defineComponent({
this.checkIfTimestamp()
this.currentPlaybackRate = this.$store.getters.getDefaultPlayback
- this.skipSilenceEnabled = this.$store.getters.getSkipSilenceEnabled
+ this.startNextVideoWithSkipSilenceEnabled = this.$store.getters.getSkipSilenceEnabled
},
mounted: function () {
this.onMountedDependOnLocalStateLoading()
@@ -1763,7 +1763,7 @@ export default defineComponent({
this.currentPlaybackRate = newRate
},
updateSkipSilence(newState) {
- this.skipSilenceEnabled = newState
+ this.startNextVideoWithSkipSilenceEnabled = newState
},
destroyPlayer: async function() {
diff --git a/src/renderer/views/Watch/Watch.vue b/src/renderer/views/Watch/Watch.vue
index f485a5aea392e..3f67165b9599c 100644
--- a/src/renderer/views/Watch/Watch.vue
+++ b/src/renderer/views/Watch/Watch.vue
@@ -40,7 +40,7 @@
:start-in-fullwindow="startNextVideoInFullwindow"
:start-in-pip="startNextVideoInPip"
:current-playback-rate="currentPlaybackRate"
- :skip-silence-enabled="skipSilenceEnabled"
+ :skip-silence-enabled="startNextVideoWithSkipSilenceEnabled"
class="videoPlayer"
@error="handlePlayerError"
@loaded="handleVideoLoaded"
From 6be694e7b8664599ae69fe3d71061523dd1d8699 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Thu, 30 Oct 2025 22:50:40 +0100
Subject: [PATCH 27/35] improve reset logic
---
src/constants.js | 2 +-
.../ft-shaka-video-player.js | 21 ++++++++++++-------
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index 073f50eb9ea46..bfa0d0adaa3fa 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -254,7 +254,7 @@ const SilenceSkip = {
SILENCE_DETECTION_MULTIPLIER: 4, // Multiplier for silence detection. Higher = more sensitive
TRICKPLAY_FAST_FORWARD_SPEED: 3, // Trickplay speed when skipping silence. Higher = faster
TRICKPLAY_DEFAULT_SPEED: 1, // Trickplay speed when not skipping silence. 1 = normal
- MIN_SILENCE_DURATION: 250, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
+ MIN_SILENCE_DURATION: 150, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
MIN_SOUND_DURATION: 5, // Min sound duration in ms. Higher to avoid false positives for short sounds.
}
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index dd1dc12400eb3..21c622f02199e 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -1261,6 +1261,14 @@ export default defineComponent({
let soundStart = null
let isSkipping = false
+ function resetSkip() {
+ gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
+ player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ isSkipping = false
+ silenceStart = null
+ soundStart = null
+ }
+
const loop = () => {
if (!player) {
cancelAnimationFrame(loopId)
@@ -1291,19 +1299,16 @@ export default defineComponent({
if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION) {
gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
setTimeout(() => {
- player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
- isSkipping = false
- silenceStart = null
- soundStart = null
+ resetSkip()
}, 25)
}
} else if (!isSilent && !isSkipping) {
- gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
- silenceStart = null
- soundStart = null
+ resetSkip()
+ } else if (isSkipping && (video_.paused || video_.ended || video_.muted)) {
+ resetSkip()
}
} else {
- player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ resetSkip()
return
}
From b20cb98e9d24f3e958b7e278273f37f121a1dd7d Mon Sep 17 00:00:00 2001
From: efb4f5ff-1298-471a-8973-3d47447115dc
<73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com>
Date: Fri, 31 Oct 2025 00:09:28 +0100
Subject: [PATCH 28/35] Update
src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 21c622f02199e..55c7ba5a46e5d 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -819,7 +819,6 @@ export default defineComponent({
if (onlyUseOverFlowMenu.value) {
uiConfig.overflowMenuButtons = [
- 'ft_screenshot',
'ft_autoplay_toggle',
props.format === 'legacy' ? 'ft_legacy_quality' : 'quality',
'playback_rate',
From 3fa2a80310f6487b09bb4d11ab3f1f409dc3c7ac Mon Sep 17 00:00:00 2001
From: efb4f5ff-1298-471a-8973-3d47447115dc
<73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com>
Date: Fri, 31 Oct 2025 00:09:54 +0100
Subject: [PATCH 29/35] Update
src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 55c7ba5a46e5d..73fe9cdf267b2 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -825,7 +825,6 @@ export default defineComponent({
'captions',
'ft_audio_tracks',
'loop',
- 'ft_skip_silence_toggle',
'picture_in_picture',
'ft_full_window',
'recenter_vr',
From 3546fbb57c7715e14159fddf867ca55f5595408b Mon Sep 17 00:00:00 2001
From: efb4f5ff-1298-471a-8973-3d47447115dc
<73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com>
Date: Fri, 31 Oct 2025 00:10:09 +0100
Subject: [PATCH 30/35] Update
src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
---
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 73fe9cdf267b2..009030c92b884 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -825,6 +825,8 @@ export default defineComponent({
'captions',
'ft_audio_tracks',
'loop',
+ 'ft_skip_silence_toggle',
+ 'ft_screenshot',
'picture_in_picture',
'ft_full_window',
'recenter_vr',
From 2d6626f475d770af6516f7c5296cf9965a924d8b Mon Sep 17 00:00:00 2001
From: some-git-user <65288184+some-git-user@users.noreply.github.com>
Date: Mon, 3 Nov 2025 20:54:37 +0100
Subject: [PATCH 31/35] Update
src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
Co-authored-by: efb4f5ff-1298-471a-8973-3d47447115dc <73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com>
---
.../player-components/SkipSilenceButton.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index 2fdac07e2dd2f..06699bde88507 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -65,7 +65,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
/** @private */
updateLocalisedStrings_() {
- this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('Video.Player.SilenceSkip.Skip Silence')
+ this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('Video.Player.Skip Silence')
this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SHUTTER_SPEED_DEFAULT : PlayerIcons.TIMER_DEFAULT)
this.currentState_.textContent = this.localization.resolve(this.skipSilenceEnabled_ ? 'ON' : 'OFF')
}
From 80819942ce63ebca7cbb13a9e342de895d9b24b2 Mon Sep 17 00:00:00 2001
From: some-git-user <65288184+some-git-user@users.noreply.github.com>
Date: Mon, 3 Nov 2025 20:54:50 +0100
Subject: [PATCH 32/35] Update static/locales/en-US.yaml
Co-authored-by: efb4f5ff-1298-471a-8973-3d47447115dc <73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com>
---
static/locales/en-US.yaml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 126a380e01c57..c2d5116346c3d 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -945,8 +945,7 @@ Video:
You appear to be offline: You appear to be offline.
Playback will resume automatically when your connection comes back: Playback will resume automatically when your connection comes back.
Skipped segment: 'Skipped {segmentCategory} segment'
- SilenceSkip:
- Skip Silence: Skip Silence
+ Skip Silence: Skip Silence
#& Playlists
Playlist:
#& About
From 4f32185831751ecc607e0955272f6f4f83caaf30 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Tue, 4 Nov 2025 00:32:08 +0100
Subject: [PATCH 33/35] fix playback rates
---
src/constants.js | 2 --
.../ft-shaka-video-player.js | 36 +++++++++----------
2 files changed, 17 insertions(+), 21 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index 6535c81d885b7..9cf8fccfb19e5 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -250,8 +250,6 @@ const ABOUT_BITCOIN_ADDRESS = '1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS'
const SilenceSkip = {
SILENCE_DETECTION_MULTIPLIER: 4, // Multiplier for silence detection. Higher = more sensitive
- TRICKPLAY_FAST_FORWARD_SPEED: 3, // Trickplay speed when skipping silence. Higher = faster
- TRICKPLAY_DEFAULT_SPEED: 1, // Trickplay speed when not skipping silence. 1 = normal
MIN_SILENCE_DURATION: 150, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
MIN_SOUND_DURATION: 5, // Min sound duration in ms. Higher to avoid false positives for short sounds.
}
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 792509d678f47..cb79557c64239 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -200,6 +200,7 @@ export default defineComponent({
let startInPip = props.startInPip
const isSilenceSkipEnabled = ref(false)
+ const trickPlayNormalSpeed = ref(props.currentPlaybackRate)
/**
* @type {{
@@ -1263,9 +1264,12 @@ export default defineComponent({
let soundStart = null
let isSkipping = false
+ trickPlayNormalSpeed.value = player.getPlaybackRate()
+ const trickPlayFastForwardSpeed = maxVideoPlaybackRate.value
+
function resetSkip() {
gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
- player.trickPlay(SilenceSkip.TRICKPLAY_DEFAULT_SPEED)
+ player.trickPlay(trickPlayNormalSpeed.value)
isSkipping = false
silenceStart = null
soundStart = null
@@ -1277,6 +1281,12 @@ export default defineComponent({
return
}
+ const currentPlaybackRate = player.getPlaybackRate()
+ // Update the trick play speed, if the user changes the playback rate
+ if (trickPlayNormalSpeed.value !== currentPlaybackRate && trickPlayFastForwardSpeed !== currentPlaybackRate) {
+ trickPlayNormalSpeed.value = player.getPlaybackRate()
+ }
+
if (isSilenceSkipEnabled.value) {
analyser.getByteTimeDomainData(amplitudeArray)
const volumeValues = Array.from(amplitudeArray)
@@ -1292,7 +1302,7 @@ export default defineComponent({
if (!silenceStart) silenceStart = now
if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION) {
gain.gain.setTargetAtTime(0, audioContext.currentTime, 0.025)
- player.trickPlay(SilenceSkip.TRICKPLAY_FAST_FORWARD_SPEED)
+ player.trickPlay(trickPlayFastForwardSpeed)
isSkipping = true
soundStart = null
}
@@ -2300,7 +2310,7 @@ export default defineComponent({
return
}
- const previousIsSilenceSkipEnabledState = isSilenceSkipEnabled.value
+ const playbackRate = isSilenceSkipEnabled.value ? trickPlayNormalSpeed.value : player.getPlaybackRate()
switch (event.key.toLowerCase()) {
case ' ':
@@ -2313,12 +2323,12 @@ export default defineComponent({
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.LARGE_REWIND:
// Rewind by 2x the time-skip interval (in seconds)
event.preventDefault()
- seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate() * 2, false, true)
+ seekBySeconds(-defaultSkipInterval.value * playbackRate * 2, false, true)
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.LARGE_FAST_FORWARD:
// Fast-Forward by 2x the time-skip interval (in seconds)
event.preventDefault()
- seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate() * 2, false, true)
+ seekBySeconds(defaultSkipInterval.value * playbackRate * 2, false, true)
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.DECREASE_VIDEO_SPEED:
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.DECREASE_VIDEO_SPEED_ALT:
@@ -2371,36 +2381,24 @@ export default defineComponent({
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_REWIND:
event.preventDefault()
- if (previousIsSilenceSkipEnabledState) {
- skipSilence()
- }
if (canChapterJump(event, 'previous')) {
// Jump to the previous chapter
video_.currentTime = props.chapters[props.currentChapterIndex - 1].startSeconds
showOverlayControls()
} else {
// Rewind by the time-skip interval (in seconds)
- seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), false, true)
- }
- if (previousIsSilenceSkipEnabledState) {
- skipSilence()
+ seekBySeconds(-defaultSkipInterval.value * playbackRate, false, true)
}
break
case KeyboardShortcuts.VIDEO_PLAYER.PLAYBACK.SMALL_FAST_FORWARD:
event.preventDefault()
- if (previousIsSilenceSkipEnabledState) {
- skipSilence()
- }
if (canChapterJump(event, 'next')) {
// Jump to the next chapter
video_.currentTime = (props.chapters[props.currentChapterIndex + 1].startSeconds)
showOverlayControls()
} else {
// Fast-Forward by the time-skip interval (in seconds)
- seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), false, true)
- }
- if (previousIsSilenceSkipEnabledState) {
- skipSilence()
+ seekBySeconds(defaultSkipInterval.value * playbackRate, false, true)
}
break
case KeyboardShortcuts.VIDEO_PLAYER.GENERAL.PICTURE_IN_PICTURE:
From 5737f36fc1e80c367bf1f813333446a4d59e094b Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Tue, 4 Nov 2025 00:32:29 +0100
Subject: [PATCH 34/35] fix translation
---
.../player-components/SkipSilenceButton.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
index 06699bde88507..a521af2559ab0 100644
--- a/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
+++ b/src/renderer/components/ft-shaka-video-player/player-components/SkipSilenceButton.js
@@ -65,7 +65,7 @@ export class SkipSilenceButton extends shaka.ui.Element {
/** @private */
updateLocalisedStrings_() {
- this.nameSpan_.textContent = this.button_.ariaLabel = i18n.t('Video.Player.Skip Silence')
+ this.nameSpan_.textContent = this.button_.ariaLabel = i18n.global.t('Video.Player.Skip Silence')
this.icon_.use(this.skipSilenceEnabled_ ? PlayerIcons.SHUTTER_SPEED_DEFAULT : PlayerIcons.TIMER_DEFAULT)
this.currentState_.textContent = this.localization.resolve(this.skipSilenceEnabled_ ? 'ON' : 'OFF')
}
From 37b82c423b2021b6750822b3cd406f97aefb0f96 Mon Sep 17 00:00:00 2001
From: some-git-user
Date: Fri, 28 Nov 2025 15:20:33 +0100
Subject: [PATCH 35/35] commit suggestion
---
src/constants.js | 4 ++--
.../components/ft-shaka-video-player/ft-shaka-video-player.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/constants.js b/src/constants.js
index d7efa04b62cfa..dcdc98d2162e2 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -250,8 +250,8 @@ const ABOUT_BITCOIN_ADDRESS = '1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS'
const SilenceSkip = {
SILENCE_DETECTION_MULTIPLIER: 4, // Multiplier for silence detection. Higher = more sensitive
- MIN_SILENCE_DURATION: 150, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
- MIN_SOUND_DURATION: 5, // Min sound duration in ms. Higher to avoid false positives for short sounds.
+ MIN_SILENCE_DURATION_MS: 150, // Min silence duration in ms. Higher for longer silence before skipping. Lower for faster reaction.
+ MIN_SOUND_DURATION_MS: 5, // Min sound duration in ms. Higher to avoid false positives for short sounds.
}
export {
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 302bbcf117a04..09c9e0d03bc5b 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -1300,7 +1300,7 @@ export default defineComponent({
if (isSilent && !isSkipping && !video_.paused && !video_.ended && !video_.muted) {
if (!silenceStart) silenceStart = now
- if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION) {
+ if (now - silenceStart > SilenceSkip.MIN_SILENCE_DURATION_MS) {
gain.gain.setTargetAtTime(0, audioContext.currentTime, 0.025)
player.trickPlay(trickPlayFastForwardSpeed)
isSkipping = true
@@ -1308,7 +1308,7 @@ export default defineComponent({
}
} else if (!isSilent && isSkipping) {
if (!soundStart) soundStart = now
- if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION) {
+ if (now - soundStart > SilenceSkip.MIN_SOUND_DURATION_MS) {
gain.gain.setTargetAtTime(1, audioContext.currentTime, 0.015)
setTimeout(() => {
resetSkip()