mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-07 03:57:09 +03:00
Improve precision of hover preview
Also fixes issue with YouTube "most-replayed" messing it up
This commit is contained in:
@@ -11,7 +11,6 @@ import { ActionType, Category, SegmentContainer, SponsorHideType, SponsorSourceT
|
|||||||
import { partition } from "../utils/arrayUtils";
|
import { partition } from "../utils/arrayUtils";
|
||||||
import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
|
import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
|
||||||
import { normalizeChapterName } from "../utils/exporter";
|
import { normalizeChapterName } from "../utils/exporter";
|
||||||
import { getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
|
|
||||||
import { findValidElement } from "../../maze-utils/src/dom";
|
import { findValidElement } from "../../maze-utils/src/dom";
|
||||||
import { addCleanupListener } from "../../maze-utils/src/cleanup";
|
import { addCleanupListener } from "../../maze-utils/src/cleanup";
|
||||||
|
|
||||||
@@ -125,34 +124,11 @@ class PreviewBar {
|
|||||||
mouseOnSeekBar = false;
|
mouseOnSeekBar = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const observer = new MutationObserver((mutations) => {
|
seekBar.addEventListener("mousemove", (e: MouseEvent) => {
|
||||||
if (!mouseOnSeekBar || !this.categoryTooltip || !this.categoryTooltipContainer) return;
|
if (!mouseOnSeekBar || !this.categoryTooltip || !this.categoryTooltipContainer) return;
|
||||||
|
|
||||||
// Only care about mutations to time tooltip
|
let noYoutubeChapters = !!tooltipTextWrapper.querySelector(".ytp-tooltip-text.ytp-tooltip-text-no-title");
|
||||||
if (!mutations.some((mutation) => (mutation.target as HTMLElement).classList.contains("ytp-tooltip-text"))) {
|
const timeInSeconds = this.decimalToTime((e.clientX - seekBar.getBoundingClientRect().x) / seekBar.clientWidth);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltipTextElements = tooltipTextWrapper.querySelectorAll(".ytp-tooltip-text");
|
|
||||||
let timeInSeconds: number | null = null;
|
|
||||||
let noYoutubeChapters = false;
|
|
||||||
|
|
||||||
for (const tooltipTextElement of tooltipTextElements) {
|
|
||||||
if (tooltipTextElement.classList.contains('ytp-tooltip-text-no-title')) noYoutubeChapters = true;
|
|
||||||
|
|
||||||
const tooltipText = tooltipTextElement.textContent;
|
|
||||||
if (tooltipText === null || tooltipText.length === 0) continue;
|
|
||||||
|
|
||||||
timeInSeconds = getFormattedTimeToSeconds(tooltipText);
|
|
||||||
|
|
||||||
if (timeInSeconds !== null) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeInSeconds === null) {
|
|
||||||
originalTooltip.style.removeProperty("display");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the segment at that location, using the shortest if multiple found
|
// Find the segment at that location, using the shortest if multiple found
|
||||||
const [normalSegments, chapterSegments] =
|
const [normalSegments, chapterSegments] =
|
||||||
@@ -198,15 +174,6 @@ class PreviewBar {
|
|||||||
this.chapterTooltip.style.textAlign = titleTooltip.style.textAlign;
|
this.chapterTooltip.style.textAlign = titleTooltip.style.textAlign;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(tooltipTextWrapper, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
addCleanupListener(() => {
|
|
||||||
observer.disconnect();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setTooltipTitle(segment: PreviewBarSegment, tooltip: HTMLElement): void {
|
private setTooltipTitle(segment: PreviewBarSegment, tooltip: HTMLElement): void {
|
||||||
@@ -920,6 +887,17 @@ class PreviewBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeToDecimal(time: number): number {
|
timeToDecimal(time: number): number {
|
||||||
|
return this.decimalTimeConverter(time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
decimalToTime(decimal: number): number {
|
||||||
|
return this.decimalTimeConverter(decimal, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decimal to time or time to decimal
|
||||||
|
*/
|
||||||
|
decimalTimeConverter(value: number, isTime: boolean): number {
|
||||||
if (this.originalChapterBarBlocks?.length > 1 && this.existingChapters.length === this.originalChapterBarBlocks?.length) {
|
if (this.originalChapterBarBlocks?.length > 1 && this.existingChapters.length === this.originalChapterBarBlocks?.length) {
|
||||||
// Parent element to still work when display: none
|
// Parent element to still work when display: none
|
||||||
const totalPixels = this.originalChapterBar.parentElement.clientWidth;
|
const totalPixels = this.originalChapterBar.parentElement.clientWidth;
|
||||||
@@ -929,8 +907,9 @@ class PreviewBar {
|
|||||||
const chapterElement = this.originalChapterBarBlocks[i];
|
const chapterElement = this.originalChapterBarBlocks[i];
|
||||||
const widthPixels = parseFloat(chapterElement.style.width.replace("px", ""));
|
const widthPixels = parseFloat(chapterElement.style.width.replace("px", ""));
|
||||||
|
|
||||||
if (time >= this.existingChapters[i].segment[1]) {
|
|
||||||
const marginPixels = chapterElement.style.marginRight ? parseFloat(chapterElement.style.marginRight.replace("px", "")) : 0;
|
const marginPixels = chapterElement.style.marginRight ? parseFloat(chapterElement.style.marginRight.replace("px", "")) : 0;
|
||||||
|
if ((isTime && value >= this.existingChapters[i].segment[1])
|
||||||
|
|| (!isTime && value >= (pixelOffset + widthPixels + marginPixels) / totalPixels)) {
|
||||||
pixelOffset += widthPixels + marginPixels;
|
pixelOffset += widthPixels + marginPixels;
|
||||||
lastCheckedChapter = i;
|
lastCheckedChapter = i;
|
||||||
} else {
|
} else {
|
||||||
@@ -944,13 +923,22 @@ class PreviewBar {
|
|||||||
const latestWidth = parseFloat(this.originalChapterBarBlocks[lastCheckedChapter + 1].style.width.replace("px", ""));
|
const latestWidth = parseFloat(this.originalChapterBarBlocks[lastCheckedChapter + 1].style.width.replace("px", ""));
|
||||||
const latestChapterDuration = latestChapter.segment[1] - latestChapter.segment[0];
|
const latestChapterDuration = latestChapter.segment[1] - latestChapter.segment[0];
|
||||||
|
|
||||||
const percentageInCurrentChapter = (time - latestChapter.segment[0]) / latestChapterDuration;
|
if (isTime) {
|
||||||
|
const percentageInCurrentChapter = (value - latestChapter.segment[0]) / latestChapterDuration;
|
||||||
const sizeOfCurrentChapter = latestWidth / totalPixels;
|
const sizeOfCurrentChapter = latestWidth / totalPixels;
|
||||||
return Math.min(1, ((pixelOffset / totalPixels) + (percentageInCurrentChapter * sizeOfCurrentChapter)));
|
return Math.min(1, ((pixelOffset / totalPixels) + (percentageInCurrentChapter * sizeOfCurrentChapter)));
|
||||||
|
} else {
|
||||||
|
const percentageInCurrentChapter = (value * totalPixels - pixelOffset) / latestWidth;
|
||||||
|
return Math.max(0, latestChapter.segment[0] + (percentageInCurrentChapter * latestChapterDuration));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.min(1, time / this.videoDuration);
|
if (isTime) {
|
||||||
|
return Math.min(1, value / this.videoDuration);
|
||||||
|
} else {
|
||||||
|
return Math.max(0, value * this.videoDuration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user