mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-10 21:47:06 +03:00
Merge pull request #958 from FlorianZahn/PersistantHighlight
Highlight Button now persists; Implements issue #953
This commit is contained in:
@@ -182,15 +182,15 @@
|
|||||||
"hideButtonsDescription": {
|
"hideButtonsDescription": {
|
||||||
"message": "This hides the buttons that appear on the YouTube player to submit skip segments."
|
"message": "This hides the buttons that appear on the YouTube player to submit skip segments."
|
||||||
},
|
},
|
||||||
|
"showSkipButton": {
|
||||||
|
"message": "Keep Skip to Highlight Button on Player"
|
||||||
|
},
|
||||||
"showInfoButton": {
|
"showInfoButton": {
|
||||||
"message": "Show Info Button On YouTube Player"
|
"message": "Show Info Button On YouTube Player"
|
||||||
},
|
},
|
||||||
"hideInfoButton": {
|
"hideInfoButton": {
|
||||||
"message": "Hide Info Button On YouTube Player"
|
"message": "Hide Info Button On YouTube Player"
|
||||||
},
|
},
|
||||||
"whatInfoButton": {
|
|
||||||
"message": "This is the button that opens up a popup in the YouTube page."
|
|
||||||
},
|
|
||||||
"autoHideInfoButton": {
|
"autoHideInfoButton": {
|
||||||
"message": "Auto-hide Info Button"
|
"message": "Auto-hide Info Button"
|
||||||
},
|
},
|
||||||
@@ -200,9 +200,6 @@
|
|||||||
"showDeleteButton": {
|
"showDeleteButton": {
|
||||||
"message": "Show Delete Button On YouTube Player"
|
"message": "Show Delete Button On YouTube Player"
|
||||||
},
|
},
|
||||||
"whatDeleteButton": {
|
|
||||||
"message": "This is the button on the YouTube player that will clear all your un-submitted segments for the current video."
|
|
||||||
},
|
|
||||||
"enableViewTracking": {
|
"enableViewTracking": {
|
||||||
"message": "Enable Skip Count Tracking"
|
"message": "Enable Skip Count Tracking"
|
||||||
},
|
},
|
||||||
@@ -442,9 +439,6 @@
|
|||||||
"showUploadButton": {
|
"showUploadButton": {
|
||||||
"message": "Show Upload Button"
|
"message": "Show Upload Button"
|
||||||
},
|
},
|
||||||
"whatUploadButton": {
|
|
||||||
"message": "This button appears on the YouTube player after you have selected a timestamp and are ready to submit."
|
|
||||||
},
|
|
||||||
"customServerAddress": {
|
"customServerAddress": {
|
||||||
"message": "SponsorBlock Server Address"
|
"message": "SponsorBlock Server Address"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,16 +75,26 @@
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
#infoButton.playerButton:not(.hidden) {
|
.autoHiding {
|
||||||
transform: translateX(0%) scale(1);
|
overflow: visible !important;
|
||||||
/* opacity is from YouTube page */
|
|
||||||
transition: transform 0.2s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#infoButton.playerButton.hidden {
|
.autoHiding:not(.hidden) {
|
||||||
|
transform: translateX(0%) scale(1);
|
||||||
|
/* opacity is from YouTube page */
|
||||||
|
transition: transform 0.25s, width 0.25s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autoHiding.hidden {
|
||||||
transform: translateX(100%) scale(0);
|
transform: translateX(100%) scale(0);
|
||||||
/* opacity is from YouTube page */
|
/* opacity is from YouTube page */
|
||||||
transition: transform 0.2s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
|
transition: transform 0.25s, width 0.25s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
|
||||||
|
|
||||||
|
width: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autoHiding.hidden.autoHideLeft {
|
||||||
|
transform: translateX(-100%) scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.playerButton.hidden {
|
.playerButton.hidden {
|
||||||
|
|||||||
@@ -288,6 +288,21 @@
|
|||||||
<div class="small-description">__MSG_hideButtonsDescription__</div>
|
<div class="small-description">__MSG_hideButtonsDescription__</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div option-type="toggle" toggle-type="reverse" sync-option="hideSkipButtonPlayerControls">
|
||||||
|
<label class="switch-container">
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
<div class="switch-label">
|
||||||
|
__MSG_showSkipButton__
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -301,14 +316,9 @@
|
|||||||
__MSG_showInfoButton__
|
__MSG_showInfoButton__
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div class="small-description">__MSG_whatInfoButton__</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -322,14 +332,12 @@
|
|||||||
__MSG_autoHideInfoButton__
|
__MSG_autoHideInfoButton__
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls">
|
<div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls">
|
||||||
<label class="switch-container">
|
<label class="switch-container">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
@@ -340,14 +348,9 @@
|
|||||||
__MSG_showDeleteButton__
|
__MSG_showDeleteButton__
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div class="small-description">__MSG_whatDeleteButton__</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -361,14 +364,10 @@
|
|||||||
__MSG_showUploadButton__
|
__MSG_showUploadButton__
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div class="small-description">__MSG_whatUploadButton__</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ interface SBConfig {
|
|||||||
hideInfoButtonPlayerControls: boolean,
|
hideInfoButtonPlayerControls: boolean,
|
||||||
hideDeleteButtonPlayerControls: boolean,
|
hideDeleteButtonPlayerControls: boolean,
|
||||||
hideUploadButtonPlayerControls: boolean,
|
hideUploadButtonPlayerControls: boolean,
|
||||||
|
hideSkipButtonPlayerControls: boolean,
|
||||||
hideDiscordLaunches: number,
|
hideDiscordLaunches: number,
|
||||||
hideDiscordLink: boolean,
|
hideDiscordLink: boolean,
|
||||||
invidiousInstances: string[],
|
invidiousInstances: string[],
|
||||||
@@ -172,6 +173,7 @@ const Config: SBObject = {
|
|||||||
hideInfoButtonPlayerControls: false,
|
hideInfoButtonPlayerControls: false,
|
||||||
hideDeleteButtonPlayerControls: false,
|
hideDeleteButtonPlayerControls: false,
|
||||||
hideUploadButtonPlayerControls: false,
|
hideUploadButtonPlayerControls: false,
|
||||||
|
hideSkipButtonPlayerControls: false,
|
||||||
hideDiscordLaunches: 0,
|
hideDiscordLaunches: 0,
|
||||||
hideDiscordLink: false,
|
hideDiscordLink: false,
|
||||||
invidiousInstances: ["invidious.snopyta.org"],
|
invidiousInstances: ["invidious.snopyta.org"],
|
||||||
|
|||||||
@@ -1307,15 +1307,8 @@ async function createButtons(): Promise<void> {
|
|||||||
if (Config.config.autoHideInfoButton && !onInvidious && controlsContainer
|
if (Config.config.autoHideInfoButton && !onInvidious && controlsContainer
|
||||||
&& playerButtons["info"]?.button && !controlsWithEventListeners.includes(controlsContainer)) {
|
&& playerButtons["info"]?.button && !controlsWithEventListeners.includes(controlsContainer)) {
|
||||||
controlsWithEventListeners.push(controlsContainer);
|
controlsWithEventListeners.push(controlsContainer);
|
||||||
playerButtons["info"].button.classList.add("hidden");
|
|
||||||
|
|
||||||
controlsContainer.addEventListener("mouseenter", () => {
|
utils.setupAutoHideAnimation(playerButtons["info"].button, controlsContainer);
|
||||||
playerButtons["info"].button.classList.remove("hidden");
|
|
||||||
});
|
|
||||||
|
|
||||||
controlsContainer.addEventListener("mouseleave", () => {
|
|
||||||
playerButtons["info"].button.classList.add("hidden");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import Config from "../config";
|
|||||||
import { SponsorTime } from "../types";
|
import { SponsorTime } from "../types";
|
||||||
import { getSkippingText } from "../utils/categoryUtils";
|
import { getSkippingText } from "../utils/categoryUtils";
|
||||||
|
|
||||||
|
import Utils from "../utils";
|
||||||
|
const utils = new Utils();
|
||||||
|
|
||||||
export interface SkipButtonControlBarProps {
|
export interface SkipButtonControlBarProps {
|
||||||
skip: (segment: SponsorTime) => void;
|
skip: (segment: SponsorTime) => void;
|
||||||
@@ -53,13 +55,20 @@ export class SkipButtonControlBar {
|
|||||||
|
|
||||||
if (leftControlsContainer && !leftControlsContainer.contains(this.container)) {
|
if (leftControlsContainer && !leftControlsContainer.contains(this.container)) {
|
||||||
leftControlsContainer.insertBefore(this.container, this.chapterText);
|
leftControlsContainer.insertBefore(this.container, this.chapterText);
|
||||||
|
|
||||||
|
if (Config.config.autoHideInfoButton) {
|
||||||
|
utils.setupAutoHideAnimation(this.skipIcon, leftControlsContainer, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enable(segment: SponsorTime, duration?: number): void {
|
enable(segment: SponsorTime, duration?: number): void {
|
||||||
if (duration) this.duration = duration;
|
if (duration) this.duration = duration;
|
||||||
this.segment = segment;
|
this.segment = segment;
|
||||||
|
|
||||||
this.refreshText();
|
this.refreshText();
|
||||||
|
this.textContainer?.classList?.remove("hidden");
|
||||||
|
utils.disableAutoHideAnimation(this.skipIcon);
|
||||||
|
|
||||||
this.startTimer();
|
this.startTimer();
|
||||||
}
|
}
|
||||||
@@ -68,7 +77,8 @@ export class SkipButtonControlBar {
|
|||||||
if (this.segment) {
|
if (this.segment) {
|
||||||
this.chapterText?.classList?.add("hidden");
|
this.chapterText?.classList?.add("hidden");
|
||||||
this.container.classList.remove("hidden");
|
this.container.classList.remove("hidden");
|
||||||
this.textContainer.innerText = getSkippingText([this.segment], false) + (this.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "");
|
this.textContainer.innerText = this.getTitle();
|
||||||
|
this.skipIcon.setAttribute("title", this.getTitle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,17 +94,42 @@ export class SkipButtonControlBar {
|
|||||||
|
|
||||||
startTimer(): void {
|
startTimer(): void {
|
||||||
this.stopTimer();
|
this.stopTimer();
|
||||||
this.timeout = setTimeout(() => this.disable(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000);
|
this.timeout = setTimeout(() => this.disableText(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable(): void {
|
disable(): void {
|
||||||
this.container.classList.add("hidden");
|
this.container.classList.add("hidden");
|
||||||
|
this.textContainer?.classList?.remove("hidden");
|
||||||
|
|
||||||
this.chapterText?.classList?.remove("hidden");
|
this.chapterText?.classList?.remove("hidden");
|
||||||
|
this.getChapterPrefix()?.classList?.remove("hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSkip(): void {
|
toggleSkip(): void {
|
||||||
this.skip(this.segment);
|
this.skip(this.segment);
|
||||||
this.disable();
|
this.disableText();
|
||||||
|
}
|
||||||
|
|
||||||
|
disableText(): void {
|
||||||
|
if (Config.config.hideVideoPlayerControls || Config.config.hideSkipButtonPlayerControls) {
|
||||||
|
this.disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textContainer?.classList?.add("hidden");
|
||||||
|
this.chapterText?.classList?.remove("hidden");
|
||||||
|
|
||||||
|
this.getChapterPrefix()?.classList?.add("hidden");
|
||||||
|
|
||||||
|
utils.enableAutoHideAnimation(this.skipIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTitle(): string {
|
||||||
|
return getSkippingText([this.segment], false) + (this.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private getChapterPrefix(): HTMLElement {
|
||||||
|
return document.querySelector(".ytp-chapter-title-prefix");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
src/utils.ts
28
src/utils.ts
@@ -183,6 +183,34 @@ export default class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupAutoHideAnimation(element: Element, container: Element, enabled = true, rightSlide = true): void {
|
||||||
|
if (enabled) element.classList.add("autoHiding");
|
||||||
|
element.classList.add("hidden");
|
||||||
|
element.classList.add("animationDone");
|
||||||
|
if (!rightSlide) element.classList.add("autoHideLeft");
|
||||||
|
|
||||||
|
container.addEventListener("mouseenter", () => {
|
||||||
|
element.classList.remove("animationDone");
|
||||||
|
|
||||||
|
// Wait for next event loop
|
||||||
|
setTimeout(() => element.classList.remove("hidden"), 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("mouseleave", () => {
|
||||||
|
if (element.classList.contains("autoHiding")) {
|
||||||
|
element.classList.add("hidden");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enableAutoHideAnimation(element: Element): void {
|
||||||
|
element.classList.add("autoHiding");
|
||||||
|
}
|
||||||
|
|
||||||
|
disableAutoHideAnimation(element: Element): void {
|
||||||
|
element.classList.remove("autoHiding");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges any overlapping timestamp ranges into single segments and returns them as a new array.
|
* Merges any overlapping timestamp ranges into single segments and returns them as a new array.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user