diff --git a/public/content.css b/public/content.css index 4751d293..b5c01e01 100644 --- a/public/content.css +++ b/public/content.css @@ -526,9 +526,27 @@ input::-webkit-inner-spin-button { .skipButtonControlBarContainer { cursor: pointer; display: flex; + color: white; } -.skipButtonControlBarContainer.hidden { +.skipButtonControlBarContainer.mobile { + bottom: 30%; + margin-left: 5px; + position: absolute; + height: 20px; + + background-color: #00000030; + opacity: 0.5; + border-radius: 10px; + padding: 4px; +} + +.skipButtonControlBarContainer.mobile > div { + margin: auto; + margin-left: 5px; +} + +.skipButtonControlBarContainer.hidden, .skipButtonControlBarContainer.mobile .hidden { display: none !important; } @@ -540,6 +558,10 @@ input::-webkit-inner-spin-button { margin: auto; } +.mobile #sbSkipIconControlBarImage { + height: 100%; +} + .sponsorBlockTooltip { position: absolute; background-color: rgba(28, 28, 28, 0.7); diff --git a/src/content.ts b/src/content.ts index 271ba1d9..24267ec6 100644 --- a/src/content.ts +++ b/src/content.ts @@ -17,6 +17,7 @@ import { getCategoryActionType } from "./utils/categoryUtils"; import { SkipButtonControlBar } from "./js-components/skipButtonControlBar"; import { Tooltip } from "./render/Tooltip"; import { getStartTimeFromUrl } from "./utils/urlParser"; +import { getControls } from "./utils/pageUtils"; // Hack to get the CSS loaded on permission-based sites (Invidious) utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); @@ -338,6 +339,8 @@ async function videoIDChange(id) { function handleMobileControlsMutations(): void { updateVisibilityOfPlayerControlsButton(); + skipButtonControlBar?.updateMobileControls(); + if (previewBar !== null) { if (document.body.contains(previewBar.container)) { const progressBarBackground = document.querySelector(".progress-bar-background"); @@ -652,7 +655,8 @@ function setupSkipButtonControlBar() { skippingSegments: [segment], openNotice: true, forceAutoSkip: true - }) + }), + onMobileYouTube }); } @@ -1249,6 +1253,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u && skippingSegments.length === 1 && getCategoryActionType(skippingSegments[0].category) === CategoryActionType.POI) { skipButtonControlBar.enable(skippingSegments[0], !Config.config.highlightCategoryUpdate ? 15 : 0); + if (onMobileYouTube) skipButtonControlBar.setShowKeybindHint(false); if (!Config.config.highlightCategoryUpdate) { new Tooltip({ @@ -1269,6 +1274,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u //send out the message saying that a sponsor message was skipped if (!Config.config.dontShowNotice || !autoSkip) { const newSkipNotice = new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer, unskipTime); + if (onMobileYouTube) newSkipNotice.setShowKeybindHint(false); skipNotices.push(newSkipNotice); activeSkipKeybindElement?.setShowKeybindHint(false); @@ -1356,27 +1362,6 @@ function shouldSkip(segment: SponsorTime): boolean { (Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")); } -function getControls(): HTMLElement | false { - const controlsSelectors = [ - // YouTube - ".ytp-right-controls", - // Mobile YouTube - ".player-controls-top", - // Invidious/videojs video element's controls element - ".vjs-control-bar", - ]; - - for (const controlsSelector of controlsSelectors) { - const controls = document.querySelectorAll(controlsSelector); - - if (controls && controls.length > 0) { - return controls[controls.length - 1]; - } - } - - return false; -} - /** Creates any missing buttons on the YouTube player if possible. */ async function createButtons(): Promise { if (onMobileYouTube) return; diff --git a/src/js-components/skipButtonControlBar.ts b/src/js-components/skipButtonControlBar.ts index a3e47362..4f5f3877 100644 --- a/src/js-components/skipButtonControlBar.ts +++ b/src/js-components/skipButtonControlBar.ts @@ -7,6 +7,7 @@ const utils = new Utils(); export interface SkipButtonControlBarProps { skip: (segment: SponsorTime) => void; + onMobileYouTube: boolean; } export class SkipButtonControlBar { @@ -18,6 +19,9 @@ export class SkipButtonControlBar { segment: SponsorTime; showKeybindHint = true; + onMobileYouTube: boolean; + + enabled = false; timeout: NodeJS.Timeout; duration = 0; @@ -26,10 +30,12 @@ export class SkipButtonControlBar { constructor(props: SkipButtonControlBarProps) { this.skip = props.skip; + this.onMobileYouTube = props.onMobileYouTube; this.container = document.createElement("div"); this.container.classList.add("skipButtonControlBarContainer"); this.container.classList.add("hidden"); + if (this.onMobileYouTube) this.container.classList.add("mobile"); this.skipIcon = document.createElement("img"); this.skipIcon.src = chrome.runtime.getURL("icons/skipIcon.svg"); @@ -50,21 +56,34 @@ export class SkipButtonControlBar { } attachToPage(): void { - const leftControlsContainer = document.querySelector(".ytp-left-controls"); + const mountingContainer = this.getMountingContainer(); this.chapterText = document.querySelector(".ytp-chapter-container"); - if (leftControlsContainer && !leftControlsContainer.contains(this.container)) { - leftControlsContainer.insertBefore(this.container, this.chapterText); - - if (Config.config.autoHideInfoButton) { - utils.setupAutoHideAnimation(this.skipIcon, leftControlsContainer, false, false); + if (mountingContainer && !mountingContainer.contains(this.container)) { + if (this.onMobileYouTube) { + mountingContainer.appendChild(this.container); + } else { + mountingContainer.insertBefore(this.container, this.chapterText); } + + if (Config.config.autoHideInfoButton && !this.onMobileYouTube) { + utils.setupAutoHideAnimation(this.skipIcon, mountingContainer, false, false); + } + } + } + + private getMountingContainer(): HTMLElement { + if (!this.onMobileYouTube) { + return document.querySelector(".ytp-left-controls"); + } else { + return document.getElementById("player-container-id"); } } enable(segment: SponsorTime, duration?: number): void { if (duration) this.duration = duration; this.segment = segment; + this.enabled = true; this.refreshText(); this.textContainer?.classList?.remove("hidden"); @@ -97,12 +116,14 @@ export class SkipButtonControlBar { this.timeout = setTimeout(() => this.disableText(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000); } - disable(): void { + disable(keepActive = false): void { this.container.classList.add("hidden"); this.textContainer?.classList?.remove("hidden"); this.chapterText?.classList?.remove("hidden"); this.getChapterPrefix()?.classList?.remove("hidden"); + + if (!keepActive) this.enabled = false; } toggleSkip(): void { @@ -110,12 +131,13 @@ export class SkipButtonControlBar { this.disableText(); } - disableText(): void { - if (Config.config.hideVideoPlayerControls || Config.config.hideSkipButtonPlayerControls) { - this.disable(); + disableText(forceNotDisable = false): void { + if (!forceNotDisable && (Config.config.hideVideoPlayerControls || Config.config.hideSkipButtonPlayerControls || this.onMobileYouTube)) { + this.disable(this.onMobileYouTube); return; } + this.container.classList.remove("hidden"); this.textContainer?.classList?.add("hidden"); this.chapterText?.classList?.remove("hidden"); @@ -124,6 +146,19 @@ export class SkipButtonControlBar { utils.enableAutoHideAnimation(this.skipIcon); } + updateMobileControls(): void { + const overlay = document.getElementById("player-control-overlay"); + + if (overlay && this.enabled) { + if (overlay?.classList?.contains("pointer-events-off")) { + this.disable(true); + } else { + this.disableText(true); + this.skipIcon.classList.remove("hidden"); + } + } + } + private getTitle(): string { return getSkippingText([this.segment], false) + (this.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : ""); } diff --git a/src/utils/pageUtils.ts b/src/utils/pageUtils.ts new file mode 100644 index 00000000..e88f7cc9 --- /dev/null +++ b/src/utils/pageUtils.ts @@ -0,0 +1,20 @@ +export function getControls(): HTMLElement | false { + const controlsSelectors = [ + // YouTube + ".ytp-right-controls", + // Mobile YouTube + ".player-controls-top", + // Invidious/videojs video element's controls element + ".vjs-control-bar", + ]; + + for (const controlsSelector of controlsSelectors) { + const controls = document.querySelectorAll(controlsSelector); + + if (controls && controls.length > 0) { + return controls[controls.length - 1]; + } + } + + return false; +} \ No newline at end of file