Skip to content

Feat: SponsorBlock improvements #1849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 29, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import Vue from 'vue'
import { mapActions } from 'vuex'
import FtSelect from '../ft-select/ft-select.vue'

export default Vue.extend({
name: 'FtSponsorBlockCategory',
components: {
'ft-select': FtSelect
},
props: {
categoryName: {
type: String,
required: true
}
},
data: function () {
return {
categoryColor: '',
skipOption: '',
skipValues: [
'autoSkip',
// 'promptToSkip',
'showInSeekBar',
'doNothing'
]
}
},
computed: {
colorValues: function () {
return this.$store.getters.getColorNames
},

colorNames: function () {
return this.colorValues.map(colorVal => {
// add spaces before capital letters
const colorName = colorVal.replace(/([A-Z])/g, ' $1').trim()
return this.$t(`Settings.Theme Settings.Main Color Theme.${colorName}`)
})
},

sponsorBlockValues: function() {
let sponsorVal = ''
switch (this.categoryName.toLowerCase()) {
case 'sponsor':
sponsorVal = this.$store.getters.getSponsorBlockSponsor
break
case 'self-promotion':
sponsorVal = this.$store.getters.getSponsorBlockSelfPromo
break
case 'interaction':
sponsorVal = this.$store.getters.getSponsorBlockInteraction
break
case 'intro':
sponsorVal = this.$store.getters.getSponsorBlockIntro
break
case 'outro':
sponsorVal = this.$store.getters.getSponsorBlockOutro
break
case 'recap':
sponsorVal = this.$store.getters.getSponsorBlockRecap
break
case 'music offtopic':
sponsorVal = this.$store.getters.getSponsorBlockMusicOffTopic
break
case 'filler':
sponsorVal = this.$store.getters.getSponsorBlockFiller
break
}
return sponsorVal
},

skipNames: function() {
return [
this.$t('Settings.SponsorBlock Settings.Skip Options.Auto Skip'),
// this.$t('Settings.SponsorBlock Settings.Skip Options.Prompt To Skip'),
this.$t('Settings.SponsorBlock Settings.Skip Options.Show In Seek Bar'),
this.$t('Settings.SponsorBlock Settings.Skip Options.Do Nothing')
]
}
},

methods: {
updateColor: function (color) {
const payload = {
color: color,
skip: this.sponsorBlockValues.skip
}
this.updateSponsorCategory(payload)
},

updateSkipOption: function (skipOption) {
const payload = {
color: this.sponsorBlockValues.color,
skip: skipOption
}

this.updateSponsorCategory(payload)
},

updateSponsorCategory: function (payload) {
switch (this.categoryName.toLowerCase()) {
case 'sponsor':
this.updateSponsorBlockSponsor(payload)
break
case 'self-promotion':
this.updateSponsorBlockSelfPromo(payload)
break
case 'interaction':
this.updateSponsorBlockInteraction(payload)
break
case 'intro':
this.updateSponsorBlockIntro(payload)
break
case 'outro':
this.updateSponsorBlockOutro(payload)
break
case 'recap':
this.updateSponsorBlockRecap(payload)
break
case 'music offtopic':
this.updateSponsorBlockMusicOffTopic(payload)
break
case 'filler':
this.updateSponsorBlockFiller(payload)
break
}
},

...mapActions([
'showToast',
'openExternalLink',
'updateSponsorBlockSponsor',
'updateSponsorBlockSelfPromo',
'updateSponsorBlockInteraction',
'updateSponsorBlockIntro',
'updateSponsorBlockOutro',
'updateSponsorBlockRecap',
'updateSponsorBlockMusicOffTopic',
'updateSponsorBlockFiller'
])
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@use "../../sass-partials/settings"
.sponsorBlockCategory
margin-top: 30px
padding: 0 10px
.sponsorTitle
font-size: x-large
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div class="sponsorBlockCategory">
<div class="sponsorTitle">
{{ $t("Video.Sponsor Block category."+categoryName) }}
</div>
<ft-select
:placeholder="$t('Settings.SponsorBlock Settings.Category Color')"
:value="sponsorBlockValues.color"
:select-names="colorNames"
:select-values="colorValues"
@change="updateColor"
/>
<ft-select
:placeholder="$t('Settings.SponsorBlock Settings.Skip Options.Skip Option')"
:value="sponsorBlockValues.skip"
:select-names="skipNames"
:select-values="skipValues"
@change="updateSkipOption"
/>
</div>
</template>
<script src="./ft-sponsor-block-category.js" />
<style scoped lang="sass" src="./ft-sponsor-block-category.sass" />
96 changes: 69 additions & 27 deletions src/renderer/components/ft-video-player/ft-video-player.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,62 @@ export default Vue.extend({
return this.$store.getters.getDisplayVideoPlayButton
},

sponsorSkips: function () {
const sponsorCats = ['sponsor',
'selfpromo',
'interaction',
'intro',
'outro',
'preview',
'music_offtopic',
'filler'
]
const autoSkip = {}
const seekBar = []
const promptSkip = {}
const categoryData = {}
sponsorCats.forEach(x => {
let sponsorVal = {}
switch (x) {
case 'sponsor':
sponsorVal = this.$store.getters.getSponsorBlockSponsor
break
case 'selfpromo':
sponsorVal = this.$store.getters.getSponsorBlockSelfPromo
break
case 'interaction':
sponsorVal = this.$store.getters.getSponsorBlockInteraction
break
case 'intro':
sponsorVal = this.$store.getters.getSponsorBlockIntro
break
case 'outro':
sponsorVal = this.$store.getters.getSponsorBlockOutro
break
case 'preview':
sponsorVal = this.$store.getters.getSponsorBlockRecap
break
case 'music_offtopic':
sponsorVal = this.$store.getters.getSponsorBlockMusicOffTopic
break
case 'filler':
sponsorVal = this.$store.getters.getSponsorBlockFiller
break
}
if (sponsorVal.skip !== 'doNothing') {
seekBar.push(x)
}
if (sponsorVal.skip === 'autoSkip') {
autoSkip[x] = true
}
if (sponsorVal.skip === 'promptToSkip') {
promptSkip[x] = true
}
categoryData[x] = sponsorVal
})
return { autoSkip, seekBar, promptSkip, categoryData }
},

maxVideoPlaybackRate: function () {
return parseInt(this.$store.getters.getMaxVideoPlaybackRate)
},
Expand Down Expand Up @@ -432,7 +488,7 @@ export default Vue.extend({
initializeSponsorBlock() {
this.sponsorBlockSkipSegments({
videoId: this.videoId,
categories: ['sponsor']
categories: this.sponsorSkips.seekBar
}).then((skipSegments) => {
if (skipSegments.length === 0) {
return
Expand All @@ -450,7 +506,8 @@ export default Vue.extend({
this.addSponsorBlockMarker({
time: startTime,
duration: endTime - startTime,
color: this.sponsorBlockCategoryColor(category)
color: 'var(--primary-color)',
category: category
})
})
})
Expand All @@ -469,10 +526,12 @@ export default Vue.extend({
}
})
if (newTime !== null && Math.abs(duration - currentTime) > 0.500) {
if (this.sponsorBlockShowSkippedToast) {
this.showSkippedSponsorSegmentInformation(skippedCategory)
if (this.sponsorSkips.autoSkip[skippedCategory]) {
if (this.sponsorBlockShowSkippedToast) {
this.showSkippedSponsorSegmentInformation(skippedCategory)
}
this.player.currentTime(newTime)
}
this.player.currentTime(newTime)
}
},

Expand All @@ -497,42 +556,25 @@ export default Vue.extend({
return this.$t('Video.Sponsor Block category.interaction')
case 'music_offtopic':
return this.$t('Video.Sponsor Block category.music offtopic')
case 'filler':
return this.$t('Video.Sponsor Block category.filler')
default:
console.error(`Unknown translation for SponsorBlock category ${category}`)
return category
}
},

sponsorBlockCategoryColor(category) {
// TODO: allow to set these colors in settings
switch (category) {
case 'sponsor':
return 'var(--accent-color)'
case 'intro':
return 'var(--accent-color)'
case 'outro':
return 'var(--accent-color)'
case 'selfpromo':
return 'var(--accent-color)'
case 'interaction':
return 'var(--accent-color)'
case 'music_offtopic':
return 'var(--accent-color)'
default:
console.error(`Unknown SponsorBlock category ${category}`)
return 'var(--accent-color)'
}
},

addSponsorBlockMarker(marker) {
const markerDiv = videojs.dom.createEl('div', {}, {})

markerDiv.className = 'sponsorBlockMarker'
markerDiv.className = `sponsorBlockMarker main${this.sponsorSkips.categoryData[marker.category].color}`
markerDiv.style.height = '100%'
markerDiv.style.position = 'absolute'
markerDiv.style.opacity = '0.6'
markerDiv.style['background-color'] = marker.color
markerDiv.style.width = (marker.duration / this.player.duration()) * 100 + '%'
markerDiv.style.marginLeft = (marker.time / this.player.duration()) * 100 + '%'
markerDiv.title = this.sponsorBlockTranslatedCategory(marker.category)

this.player.el().querySelector('.vjs-progress-holder').appendChild(markerDiv)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,30 @@ import FtCard from '../ft-card/ft-card.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtSponsorBlockCategory from '../ft-sponsor-block-category/ft-sponsor-block-category.vue'

export default Vue.extend({
name: 'SponsorBlockSettings',
components: {
'ft-card': FtCard,
'ft-toggle-switch': FtToggleSwitch,
'ft-input': FtInput,
'ft-flex-box': FtFlexBox
'ft-flex-box': FtFlexBox,
'ft-sponsor-block-category': FtSponsorBlockCategory
},
data: function () {
return {
categories: [
'sponsor',
'self-promotion',
'interaction',
'intro',
'outro',
'recap',
'music offtopic',
'filler'
]
}
},
computed: {
useSponsorBlock: function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
@input="handleUpdateSponsorBlockUrl"
/>
</ft-flex-box>
<ft-flex-box>
<ft-sponsor-block-category
v-for="category in categories"
:key="category"
:category-name="category"
/>
</ft-flex-box>
</div>
</details>
</template>
Expand Down
Loading