fix: stubtitle

This commit is contained in:
Gabe
2025-10-13 14:15:14 +08:00
parent 36973b8693
commit 4e9293ae0f
3 changed files with 66 additions and 8 deletions

View File

@@ -101,8 +101,6 @@ background-color: rgba(0, 0, 0, 0.5);
color: white;
line-height: 1.3;
text-shadow: 1px 1px 2px black;
opacity: 0;
transition: opacity 0.3s ease-in-out;
display: inline-block`;
const SUBTITLE_ORIGIN_STYLE = `font-size: clamp(1.5rem, 3cqw, 3rem);`;

View File

@@ -10,9 +10,11 @@ export class BilingualSubtitleManager {
#formattedSubtitles = [];
#translationService;
#captionWindowEl = null;
#paperEl = null;
#currentSubtitleIndex = -1;
#preTranslateSeconds = 100;
#setting = {};
#isAdPlaying = false;
/**
* @param {object} options
@@ -56,6 +58,14 @@ export class BilingualSubtitleManager {
this.#formattedSubtitles = [];
}
/**
* 更新广告播放状态。
*/
setIsAdPlaying(isPlaying) {
this.#isAdPlaying = isPlaying;
this.onTimeUpdate();
}
/**
* 创建并配置用于显示字幕的 DOM 元素。
*/
@@ -68,6 +78,7 @@ export class BilingualSubtitleManager {
height: "100%",
left: "0",
top: "0",
pointerEvents: "none",
});
const paper = document.createElement("div");
@@ -81,16 +92,20 @@ export class BilingualSubtitleManager {
textAlign: "center",
containerType: "inline-size",
zIndex: "2147483647",
pointerEvents: "auto",
display: "none",
});
this.#paperEl = paper;
this.#captionWindowEl = document.createElement("div");
this.#captionWindowEl.className = `kiss-caption-window`;
this.#captionWindowEl.style.cssText = this.#setting.windowStyle;
this.#captionWindowEl.style.pointerEvents = "auto";
this.#captionWindowEl.style.cursor = "grab";
this.#captionWindowEl.style.opacity = "1";
paper.appendChild(this.#captionWindowEl);
container.appendChild(paper);
this.#paperEl.appendChild(this.#captionWindowEl);
container.appendChild(this.#paperEl);
const videoContainer = this.#videoEl.parentElement?.parentElement;
if (!videoContainer) {
@@ -101,7 +116,7 @@ export class BilingualSubtitleManager {
videoContainer.style.position = "relative";
videoContainer.appendChild(container);
this.#enableDragging(paper, container, this.#captionWindowEl);
this.#enableDragging(this.#paperEl, container, this.#captionWindowEl);
}
/**
@@ -230,7 +245,12 @@ export class BilingualSubtitleManager {
* @param {object | null} subtitle - 字幕对象,或 null 用于清空。
*/
#updateCaptionDisplay(subtitle) {
if (!this.#captionWindowEl) return;
if (!this.#paperEl || !this.#captionWindowEl) return;
if (this.#isAdPlaying) {
this.#paperEl.style.display = "none";
return;
}
if (subtitle) {
const p1 = document.createElement("p");
@@ -247,9 +267,9 @@ export class BilingualSubtitleManager {
this.#captionWindowEl.replaceChildren(p2);
}
this.#captionWindowEl.style.opacity = "1";
this.#paperEl.style.display = "block";
} else {
this.#captionWindowEl.style.opacity = "0";
this.#paperEl.style.display = "none";
}
}

View File

@@ -15,6 +15,7 @@ import { i18n } from "../config";
const VIDEO_SELECT = "#container video";
const CONTORLS_SELECT = ".ytp-right-controls";
const YT_CAPTION_SELECT = "#ytp-caption-window-container";
const YT_AD_SELECT = ".video-ads";
class YouTubeCaptionProvider {
#setting = {};
@@ -45,6 +46,7 @@ class YouTubeCaptionProvider {
}
}
});
window.addEventListener("yt-navigate-finish", () => {
setTimeout(() => {
if (this.#toggleButton) {
@@ -54,9 +56,46 @@ class YouTubeCaptionProvider {
this.#doubleClick();
}, 1000);
});
this.#waitForElement(CONTORLS_SELECT, (ytControls) =>
this.#injectToggleButton(ytControls)
);
this.#waitForElement(YT_AD_SELECT, (adContainer) => {
this.#moAds(adContainer);
});
}
#moAds(adContainer) {
const adSlector = ".ytp-ad-player-overlay-layout";
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === "childList") {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1 && node.matches(adSlector)) {
logger.debug("Youtube Provider: AD start playing!", node);
// todo: 顺带把广告快速跳过
if (this.#managerInstance) {
this.#managerInstance.setIsAdPlaying(true);
}
}
});
mutation.removedNodes.forEach((node) => {
if (node.nodeType === 1 && node.matches(adSlector)) {
logger.debug("Youtube Provider: Ad ends!");
if (this.#managerInstance) {
this.#managerInstance.setIsAdPlaying(false);
}
}
});
}
}
});
observer.observe(adContainer, {
childList: true,
subtree: true,
});
}
#waitForElement(selector, callback) {
@@ -517,6 +556,7 @@ class YouTubeCaptionProvider {
let subtitles = this.#processSubtitles({ flatEvents });
const isPoor = this.#isQualityPoor(subtitles);
logger.debug("Youtube Provider: isQualityPoor", { isPoor, subtitles });
if (isPoor) {
subtitles = this.#processSubtitles({ flatEvents, usePause: true });
}