diff --git a/src/components/PreferencesPage.vue b/src/components/PreferencesPage.vue
index 507c598a..65a381f7 100644
--- a/src/components/PreferencesPage.vue
+++ b/src/components/PreferencesPage.vue
@@ -184,83 +184,13 @@
/>
-
-
-
-
-
-
-
-
-
@@ -391,16 +331,19 @@ export default {
selectedAuthInstance: null,
instances: [],
sponsorBlock: true,
- skipSponsor: true,
- skipIntro: false,
- skipOutro: false,
- skipPreview: false,
- skipInteraction: true,
- skipSelfPromo: true,
- skipMusicOffTopic: true,
- skipHighlight: false,
- skipFiller: false,
+ skipOptions: new Map([
+ ["sponsor", { value: "auto", label: "actions.skip_sponsors" }],
+ ["intro", { value: "no", label: "actions.skip_intro" }],
+ ["outro", { value: "no", label: "actions.skip_outro" }],
+ ["preview", { value: "no", label: "actions.skip_preview" }],
+ ["interaction", { value: "auto", label: "actions.skip_interaction" }],
+ ["selfpromo", { value: "auto", label: "actions.skip_self_promo" }],
+ ["music_offtopic", { value: "auto", label: "actions.skip_non_music" }],
+ ["poi_highlight", { value: "no", label: "actions.skip_highlight" }],
+ ["filler", { value: "no", label: "actions.skip_filler_tangent" }],
+ ]),
showMarkers: true,
+ minSegmentLength: 0,
selectedTheme: "dark",
autoPlayVideo: true,
listen: false,
@@ -497,55 +440,25 @@ export default {
this.selectedAuthInstance = this.getPreferenceString("auth_instance_url", this.selectedInstance);
this.sponsorBlock = this.getPreferenceBoolean("sponsorblock", true);
- if (localStorage.getItem("selectedSkip") !== null) {
- var skipList = localStorage.getItem("selectedSkip").split(",");
- this.skipSponsor =
- this.skipIntro =
- this.skipOutro =
- this.skipPreview =
- this.skipInteraction =
- this.skipSelfPromo =
- this.skipMusicOffTopic =
- this.skipHighlight =
- this.skipFiller =
- false;
+ var skipOptions, skipList;
+ if ((skipOptions = this.getPreferenceJSON("skipOptions")) !== undefined) {
+ Object.entries(skipOptions).forEach(([key, value]) => {
+ var opt = this.skipOptions.get(key);
+ if (opt !== undefined) opt.value = value;
+ else console.log("Unknown sponsor type: " + key);
+ });
+ } else if ((skipList = this.getPreferenceString("selectedSkip")) !== undefined) {
+ skipList = skipList.split(",");
+ this.skipOptions.forEach(opt => (opt.value = "no"));
skipList.forEach(skip => {
- switch (skip) {
- case "sponsor":
- this.skipSponsor = true;
- break;
- case "intro":
- this.skipIntro = true;
- break;
- case "outro":
- this.skipOutro = true;
- break;
- case "preview":
- this.skipPreview = true;
- break;
- case "interaction":
- this.skipInteraction = true;
- break;
- case "selfpromo":
- this.skipSelfPromo = true;
- break;
- case "music_offtopic":
- this.skipMusicOffTopic = true;
- break;
- case "poi_highlight":
- this.skipHighlight = true;
- break;
- case "filler":
- this.skipFiller = true;
- break;
- default:
- console.log("Unknown sponsor type: " + skip);
- break;
- }
+ var opt = this.skipOptions.get(skip);
+ if (opt !== undefined) opt.value = "auto";
+ else console.log("Unknown sponsor type: " + skip);
});
}
this.showMarkers = this.getPreferenceBoolean("showMarkers", true);
+ this.minSegmentLength = Math.max(this.getPreferenceNumber("minSegmentLength", 0), 0);
this.selectedTheme = this.getPreferenceString("theme", "dark");
this.autoPlayVideo = this.getPreferenceBoolean("playerAutoPlay", true);
this.listen = this.getPreferenceBoolean("listen", false);
@@ -594,19 +507,12 @@ export default {
localStorage.setItem("auth_instance_url", this.selectedAuthInstance);
localStorage.setItem("sponsorblock", this.sponsorBlock);
- var sponsorSelected = [];
- if (this.skipSponsor) sponsorSelected.push("sponsor");
- if (this.skipIntro) sponsorSelected.push("intro");
- if (this.skipOutro) sponsorSelected.push("outro");
- if (this.skipPreview) sponsorSelected.push("preview");
- if (this.skipInteraction) sponsorSelected.push("interaction");
- if (this.skipSelfPromo) sponsorSelected.push("selfpromo");
- if (this.skipMusicOffTopic) sponsorSelected.push("music_offtopic");
- if (this.skipHighlight) sponsorSelected.push("poi_highlight");
- if (this.skipFiller) sponsorSelected.push("filler");
- localStorage.setItem("selectedSkip", sponsorSelected);
+ var skipOptions = {};
+ this.skipOptions.forEach((v, k) => (skipOptions[k] = v.value));
+ localStorage.setItem("skipOptions", JSON.stringify(skipOptions));
localStorage.setItem("showMarkers", this.showMarkers);
+ localStorage.setItem("minSegmentLength", this.minSegmentLength);
localStorage.setItem("theme", this.selectedTheme);
localStorage.setItem("playerAutoPlay", this.autoPlayVideo);
localStorage.setItem("listen", this.listen);
diff --git a/src/components/VideoPlayer.vue b/src/components/VideoPlayer.vue
index 7a3012ac..6bceb412 100644
--- a/src/components/VideoPlayer.vue
+++ b/src/components/VideoPlayer.vue
@@ -6,6 +6,17 @@
:class="{ 'player-container': !isEmbed }"
>
+
@@ -51,6 +62,7 @@ export default {
lastUpdate: new Date().getTime(),
initialSeekComplete: false,
destroying: false,
+ inSegment: false,
};
},
computed: {
@@ -88,7 +100,7 @@ export default {
this.hotkeysPromise.then(() => {
var self = this;
this.$hotkeys(
- "f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.",
+ "f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.,return",
function (e, handler) {
const videoEl = self.$refs.videoEl;
switch (handler.key) {
@@ -184,6 +196,9 @@ export default {
case "shift+.":
self.$player.trickPlay(Math.min(videoEl.playbackRate + 0.25, 2));
break;
+ case "return":
+ self.skipSegment(videoEl);
+ break;
}
},
);
@@ -361,17 +376,11 @@ export default {
this.$emit("timeupdate", time);
this.updateProgressDatabase(time);
if (this.sponsors && this.sponsors.segments) {
- this.sponsors.segments.map(segment => {
- if (!segment.skipped || this.selectedAutoLoop) {
- const end = segment.segment[1];
- if (time >= segment.segment[0] && time < end) {
- console.log("Skipped segment at " + time);
- videoEl.currentTime = end;
- segment.skipped = true;
- return;
- }
- }
- });
+ const segment = this.findCurrentSegment(time);
+ this.inSegment = !!segment;
+ if (segment?.autoskip && (!segment.skipped || this.selectedAutoLoop)) {
+ this.skipSegment(videoEl, segment);
+ }
}
});
@@ -398,6 +407,21 @@ export default {
//TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
},
+ findCurrentSegment(time) {
+ return this.sponsors?.segments?.find(s => time >= s.segment[0] && time < s.segment[1]);
+ },
+ onClickSkipSegment() {
+ const videoEl = this.$refs.videoEl;
+ this.skipSegment(videoEl);
+ },
+ skipSegment(videoEl, segment) {
+ const time = videoEl.currentTime;
+ if (!segment) segment = this.findCurrentSegment(time);
+ if (!segment) return;
+ console.log("Skipped segment at " + time);
+ videoEl.currentTime = segment.segment[1];
+ segment.skipped = true;
+ },
setPlayerAttrs(localPlayer, videoEl, uri, mime, shaka) {
const url = "/watch?v=" + this.video.id;
@@ -678,6 +702,11 @@ export default {
},
watch: {
sponsors() {
+ const skipOptions = this.getPreferenceJSON("skipOptions", {});
+ this.sponsors?.segments?.forEach(segment => {
+ const option = skipOptions[segment.category];
+ segment.autoskip = option === undefined || option === "auto";
+ });
if (this.getPreferenceBoolean("showMarkers", true)) {
this.shakaPromise.then(() => {
this.updateMarkers();
@@ -719,4 +748,34 @@ export default {
background-color: rgba(0, 0, 0, 0.6) !important;
padding: 0.09em 0;
}
+
+.skip-segment-button {
+ /* position button above player overlay */
+ z-index: 1000;
+
+ position: absolute;
+ transform: translate(0, -50%);
+ top: 50%;
+ right: 0;
+
+ background-color: rgb(0 0 0 / 0.5);
+ border: 2px rgba(255, 255, 255, 0.75) solid;
+ border-right: 0;
+ border-radius: 0.75em;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ padding: 0.5em;
+
+ /* center text vertically */
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ line-height: 1.5em;
+}
+
+.skip-segment-button .material-icons-round {
+ font-size: 1.6em !important;
+ line-height: inherit !important;
+}
diff --git a/src/components/WatchVideo.vue b/src/components/WatchVideo.vue
index 7af3e776..7b57b39b 100644
--- a/src/components/WatchVideo.vue
+++ b/src/components/WatchVideo.vue
@@ -367,15 +367,28 @@ export default {
return this.fetchJson(this.apiUrl() + "/streams/" + this.getVideoId());
},
async fetchSponsors() {
- return await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
- category:
- '["' +
- this.getPreferenceString("selectedSkip", "sponsor,interaction,selfpromo,music_offtopic").replaceAll(
- ",",
- '","',
- ) +
- '"]',
+ var selectedSkip = this.getPreferenceString(
+ "selectedSkip",
+ "sponsor,interaction,selfpromo,music_offtopic",
+ ).split(",");
+ const skipOptions = this.getPreferenceJSON("skipOptions");
+ if (skipOptions !== undefined) {
+ selectedSkip = Object.keys(skipOptions).filter(
+ k => skipOptions[k] !== undefined && skipOptions[k] !== "no",
+ );
+ }
+
+ const sponsors = await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
+ category: JSON.stringify(selectedSkip),
});
+
+ const minSegmentLength = Math.max(this.getPreferenceNumber("minSegmentLength", 0), 0);
+ sponsors.segments = sponsors.segments.filter(segment => {
+ const length = segment.segment[1] - segment.segment[0];
+ return length >= minSegmentLength;
+ });
+
+ return sponsors;
},
toggleComments() {
this.showComments = !this.showComments;
diff --git a/src/locales/en.json b/src/locales/en.json
index 1f9e94d4..99edcf41 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -30,6 +30,8 @@
"back": "Back",
"uses_api_from": "Uses the API from ",
"enable_sponsorblock": "Enable Sponsorblock",
+ "skip_button_only": "Show skip button",
+ "skip_automatically": "Automatically",
"skip_sponsors": "Skip Sponsors",
"skip_intro": "Skip Intermission/Intro Animation",
"skip_outro": "Skip Endcards/Credits",
@@ -40,6 +42,8 @@
"skip_highlight": "Skip Highlight",
"skip_filler_tangent": "Skip Filler Tangent",
"show_markers": "Show Markers on Player",
+ "min_segment_length": "Minimum Segment Length (in seconds)",
+ "skip_segment": "Skip Segment",
"theme": "Theme",
"auto": "Auto",
"dark": "Dark",
diff --git a/src/main.js b/src/main.js
index 19a037de..e27ff57b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -162,6 +162,15 @@ const mixin = {
return Number(value);
} else return defaultVal;
},
+ getPreferenceJSON(key, defaultVal) {
+ var value;
+ if (
+ (value = new URLSearchParams(window.location.search).get(key)) !== null ||
+ (this.testLocalStorage && (value = localStorage.getItem(key)) !== null)
+ ) {
+ return JSON.parse(value);
+ } else return defaultVal;
+ },
apiUrl() {
return this.getPreferenceString("instance", "https://pipedapi.kavin.rocks");
},