Feat: SponsorBlock improvements (#1849)

* Add setting for each SB category

* Update SB Settings Component

* Show other SB categories in seek bar

* Use camelCase for SponsorBlock values

Co-authored-by: PikachuEXE <pikachuexe@gmail.com>

* change "Don't Skip" to "Do Nothing" in locale

* improve styling of sponsorblock settings

* add filler category, don't repeat colors

* Fix JS format issue caused during code conflict resolving

* make sponsor block markers transparent

* change opacity to 0.6

Co-authored-by: PikachuEXE <pikachuexe@gmail.com>
This commit is contained in:
ChunkyProgrammer 2022-05-29 16:36:59 -04:00 committed by GitHub
parent 052a1fb65c
commit dfb28b1d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 350 additions and 110 deletions

View File

@ -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'
])
}
})

View File

@ -0,0 +1,6 @@
@use "../../sass-partials/settings"
.sponsorBlockCategory
margin-top: 30px
padding: 0 10px
.sponsorTitle
font-size: x-large

View File

@ -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" />

View File

@ -188,6 +188,62 @@ export default Vue.extend({
return this.$store.getters.getDisplayVideoPlayButton 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 () { maxVideoPlaybackRate: function () {
return parseInt(this.$store.getters.getMaxVideoPlaybackRate) return parseInt(this.$store.getters.getMaxVideoPlaybackRate)
}, },
@ -459,7 +515,7 @@ export default Vue.extend({
initializeSponsorBlock() { initializeSponsorBlock() {
this.sponsorBlockSkipSegments({ this.sponsorBlockSkipSegments({
videoId: this.videoId, videoId: this.videoId,
categories: ['sponsor'] categories: this.sponsorSkips.seekBar
}).then((skipSegments) => { }).then((skipSegments) => {
if (skipSegments.length === 0) { if (skipSegments.length === 0) {
return return
@ -477,7 +533,8 @@ export default Vue.extend({
this.addSponsorBlockMarker({ this.addSponsorBlockMarker({
time: startTime, time: startTime,
duration: endTime - startTime, duration: endTime - startTime,
color: this.sponsorBlockCategoryColor(category) color: 'var(--primary-color)',
category: category
}) })
}) })
}) })
@ -496,11 +553,13 @@ export default Vue.extend({
} }
}) })
if (newTime !== null && Math.abs(duration - currentTime) > 0.500) { if (newTime !== null && Math.abs(duration - currentTime) > 0.500) {
if (this.sponsorSkips.autoSkip[skippedCategory]) {
if (this.sponsorBlockShowSkippedToast) { if (this.sponsorBlockShowSkippedToast) {
this.showSkippedSponsorSegmentInformation(skippedCategory) this.showSkippedSponsorSegmentInformation(skippedCategory)
} }
this.player.currentTime(newTime) this.player.currentTime(newTime)
} }
}
}, },
showSkippedSponsorSegmentInformation(category) { showSkippedSponsorSegmentInformation(category) {
@ -524,42 +583,25 @@ export default Vue.extend({
return this.$t('Video.Sponsor Block category.interaction') return this.$t('Video.Sponsor Block category.interaction')
case 'music_offtopic': case 'music_offtopic':
return this.$t('Video.Sponsor Block category.music offtopic') return this.$t('Video.Sponsor Block category.music offtopic')
case 'filler':
return this.$t('Video.Sponsor Block category.filler')
default: default:
console.error(`Unknown translation for SponsorBlock category ${category}`) console.error(`Unknown translation for SponsorBlock category ${category}`)
return 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) { addSponsorBlockMarker(marker) {
const markerDiv = videojs.dom.createEl('div', {}, {}) 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.height = '100%'
markerDiv.style.position = 'absolute' markerDiv.style.position = 'absolute'
markerDiv.style.opacity = '0.6'
markerDiv.style['background-color'] = marker.color markerDiv.style['background-color'] = marker.color
markerDiv.style.width = (marker.duration / this.player.duration()) * 100 + '%' markerDiv.style.width = (marker.duration / this.player.duration()) * 100 + '%'
markerDiv.style.marginLeft = (marker.time / 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) this.player.el().querySelector('.vjs-progress-holder').appendChild(markerDiv)
}, },

View File

@ -4,6 +4,7 @@ import FtCard from '../ft-card/ft-card.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue' import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtInput from '../ft-input/ft-input.vue' import FtInput from '../ft-input/ft-input.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.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({ export default Vue.extend({
name: 'SponsorBlockSettings', name: 'SponsorBlockSettings',
@ -11,7 +12,22 @@ export default Vue.extend({
'ft-card': FtCard, 'ft-card': FtCard,
'ft-toggle-switch': FtToggleSwitch, 'ft-toggle-switch': FtToggleSwitch,
'ft-input': FtInput, '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: { computed: {
useSponsorBlock: function () { useSponsorBlock: function () {

View File

@ -32,6 +32,13 @@
@input="handleUpdateSponsorBlockUrl" @input="handleUpdateSponsorBlockUrl"
/> />
</ft-flex-box> </ft-flex-box>
<ft-flex-box>
<ft-sponsor-block-category
v-for="category in categories"
:key="category"
:category-name="category"
/>
</ft-flex-box>
</div> </div>
</details> </details>
</template> </template>

View File

@ -34,31 +34,6 @@ export default Vue.extend({
'dark', 'dark',
'black', 'black',
'dracula' 'dracula'
],
colorValues: [
'Red',
'Pink',
'Purple',
'DeepPurple',
'Indigo',
'Blue',
'LightBlue',
'Cyan',
'Teal',
'Green',
'LightGreen',
'Lime',
'Yellow',
'Amber',
'Orange',
'DeepOrange',
'DraculaCyan',
'DraculaGreen',
'DraculaOrange',
'DraculaPink',
'DraculaPurple',
'DraculaRed',
'DraculaYellow'
] ]
} }
}, },
@ -120,32 +95,16 @@ export default Vue.extend({
] ]
}, },
colorValues: function () {
return this.$store.getters.getColorNames
},
colorNames: function () { colorNames: function () {
return [ return this.colorValues.map(colorVal => {
this.$t('Settings.Theme Settings.Main Color Theme.Red'), // add spaces before capital letters
this.$t('Settings.Theme Settings.Main Color Theme.Pink'), const colorName = colorVal.replace(/([A-Z])/g, ' $1').trim()
this.$t('Settings.Theme Settings.Main Color Theme.Purple'), return this.$t(`Settings.Theme Settings.Main Color Theme.${colorName}`)
this.$t('Settings.Theme Settings.Main Color Theme.Deep Purple'), })
this.$t('Settings.Theme Settings.Main Color Theme.Indigo'),
this.$t('Settings.Theme Settings.Main Color Theme.Blue'),
this.$t('Settings.Theme Settings.Main Color Theme.Light Blue'),
this.$t('Settings.Theme Settings.Main Color Theme.Cyan'),
this.$t('Settings.Theme Settings.Main Color Theme.Teal'),
this.$t('Settings.Theme Settings.Main Color Theme.Green'),
this.$t('Settings.Theme Settings.Main Color Theme.Light Green'),
this.$t('Settings.Theme Settings.Main Color Theme.Lime'),
this.$t('Settings.Theme Settings.Main Color Theme.Yellow'),
this.$t('Settings.Theme Settings.Main Color Theme.Amber'),
this.$t('Settings.Theme Settings.Main Color Theme.Orange'),
this.$t('Settings.Theme Settings.Main Color Theme.Deep Orange'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Cyan'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Green'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Orange'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Pink'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Purple'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Red'),
this.$t('Settings.Theme Settings.Main Color Theme.Dracula Yellow')
]
} }
}, },
mounted: function () { mounted: function () {

View File

@ -215,6 +215,38 @@ const state = {
saveWatchedProgress: true, saveWatchedProgress: true,
sponsorBlockShowSkippedToast: true, sponsorBlockShowSkippedToast: true,
sponsorBlockUrl: 'https://sponsor.ajay.app', sponsorBlockUrl: 'https://sponsor.ajay.app',
sponsorBlockSponsor: {
color: 'Blue',
skip: 'autoSkip'
},
sponsorBlockSelfPromo: {
color: 'Yellow',
skip: 'showInSeekBar'
},
sponsorBlockInteraction: {
color: 'Green',
skip: 'showInSeekBar'
},
sponsorBlockIntro: {
color: 'Orange',
skip: 'doNothing'
},
sponsorBlockOutro: {
color: 'Orange',
skip: 'doNothing'
},
sponsorBlockRecap: {
color: 'Orange',
skip: 'doNothing'
},
sponsorBlockMusicOffTopic: {
color: 'Orange',
skip: 'doNothing'
},
sponsorBlockFiller: {
color: 'Orange',
skip: 'doNothing'
},
thumbnailPreference: '', thumbnailPreference: '',
useProxy: false, useProxy: false,
useRssFeeds: false, useRssFeeds: false,

View File

@ -26,30 +26,30 @@ const state = {
type: 'all', type: 'all',
duration: '' duration: ''
}, },
colorClasses: [ colorNames: [
'mainRed', 'Red',
'mainPink', 'Pink',
'mainPurple', 'Purple',
'mainDeepPurple', 'DeepPurple',
'mainIndigo', 'Indigo',
'mainBlue', 'Blue',
'mainLightBlue', 'LightBlue',
'mainCyan', 'Cyan',
'mainTeal', 'Teal',
'mainGreen', 'Green',
'mainLightGreen', 'LightGreen',
'mainLime', 'Lime',
'mainYellow', 'Yellow',
'mainAmber', 'Amber',
'mainOrange', 'Orange',
'mainDeepOrange', 'DeepOrange',
'mainDraculaCyan', 'DraculaCyan',
'mainDraculaGreen', 'DraculaGreen',
'mainDraculaOrange', 'DraculaOrange',
'mainDraculaPink', 'DraculaPink',
'mainDraculaPurple', 'DraculaPurple',
'mainDraculaRed', 'DraculaRed',
'mainDraculaYellow' 'DraculaYellow'
], ],
colorValues: [ colorValues: [
'#d50000', '#d50000',
@ -106,6 +106,10 @@ const getters = {
return state.searchSettings return state.searchSettings
}, },
getColorNames () {
return state.colorNames
},
getColorValues () { getColorValues () {
return state.colorValues return state.colorValues
}, },
@ -296,8 +300,8 @@ const actions = {
}, },
getRandomColorClass () { getRandomColorClass () {
const randomInt = Math.floor(Math.random() * state.colorClasses.length) const randomInt = Math.floor(Math.random() * state.colorNames.length)
return state.colorClasses[randomInt] return 'main' + state.colorNames[randomInt]
}, },
getRandomColor () { getRandomColor () {

View File

@ -337,6 +337,13 @@ Settings:
Enable SponsorBlock: Enable SponsorBlock Enable SponsorBlock: Enable SponsorBlock
'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API Url (Default is https://sponsor.ajay.app) 'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock API Url (Default is https://sponsor.ajay.app)
Notify when sponsor segment is skipped: Notify when sponsor segment is skipped Notify when sponsor segment is skipped: Notify when sponsor segment is skipped
Skip Options:
Skip Option: Skip Option
Auto Skip: Auto Skip
Show In Seek Bar: Show In Seek Bar
Prompt To Skip: Prompt To Skip
Do Nothing: Do Nothing
Category Color: Category Color
Download Settings: Download Settings:
Download Settings: Download Settings Download Settings: Download Settings
Ask Download Path: Ask for download path Ask Download Path: Ask for download path
@ -537,12 +544,14 @@ Video:
Publicationtemplate: $ % ago Publicationtemplate: $ % ago
Skipped segment: Skipped segment Skipped segment: Skipped segment
Sponsor Block category: Sponsor Block category:
sponsor: sponsor sponsor: Sponsor
intro: intro intro: Intro
outro: outro outro: Outro
self-promotion: self-promotion self-promotion: Self-Promotion
interaction: interaction interaction: Interaction
music offtopic: music offtopic music offtopic: Music Offtopic
recap: Recap
filler: Filler
External Player: External Player:
# $ is replaced with the external player # $ is replaced with the external player
OpenInTemplate: Open in $ OpenInTemplate: Open in $