odedstr / youtube-full-captions

MIT License
1 stars 1 forks source link

In "Translate automatically" mode, they don't work. #1

Open milenamilka755 opened 1 month ago

milenamilka755 commented 1 month ago

English-generated automatically-works.

When switched to a language other than English-it does not work.

Please correct.

milenamilka755 commented 1 month ago

So far I have been using the extension: https://chromewebstore.google.com/detail/hkbdddpiemdeibjoknnofflfgbgnebcm and there are subtitles on 1 line of work in languages other than English. Unfortunately, soon after switching to Manifest V3 the plug-in will stop working. Your plugin is the only alternative as long as it will work in languages other than English. Adding a window with options to change font size, color, and position would be nice. (Additional other options for full-screen mode).

odedstr commented 1 month ago

@milenamilka755 I'd like to try and fix this issue with languages, can you give me an example for a video with auto-generated subtitles other than English? I'm noting also the request for size and color. Regarding position, you can drag the subtitles vertically, even outside the video window.

milenamilka755 commented 1 month ago

I fix little the code.

`if (typeof resizeObserver === 'undefined') { let resizeObserver = null; let hide_captions_timeout_handle = null; let current_caption = "";

chrome.runtime.onMessage.addListener(
    async function (request, sender, sendResponse) {
        if (request.message === "turnOn") {
            console.log("Turn on message received");
            await turnOn();
        } else if (request.message === "turnOff") {
            location.reload();
        }
    }
);

function waitForElement(selector, timeout = 30000) {
    return new Promise((resolve, reject) => {
        const intervalTime = 100;
        let elapsedTime = 0;

        const interval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                console.log(`Element ${selector} found`);
                clearInterval(interval);
                resolve(element);
            } else if (timeout !== -1 && elapsedTime > timeout) {
                clearInterval(interval);
                reject(new Error(`Element with selector "${selector}" not found within ${timeout}ms`));
            }
            elapsedTime += intervalTime;
        }, intervalTime);
    });
}

async function turnOn() {
    try {
        await waitForElement("button.ytp-subtitles-button", -1);

        const youtube_cc_button_unpressed = document.querySelector('button.ytp-subtitles-button[aria-pressed="false"]');
        if (youtube_cc_button_unpressed !== null) {
            console.log("Turning on YouTube subtitles");
            youtube_cc_button_unpressed.click();
        }

        const captions_container = document.createElement("div");
        captions_container.classList.add("youtube-full-captions-container");
        captions_container.style.position = 'absolute';
        captions_container.style.bottom = '20px';
        captions_container.style.left = '50%';
        captions_container.style.transform = 'translateX(-50%)';
        captions_container.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        captions_container.style.padding = '10px';
        captions_container.style.zIndex = '9999';
        captions_container.innerHTML = "<div class='youtube-full-captions-text' style='color: white;'></div>";

        await waitForElement("#player", -1);
        let player_element = document.querySelector("#player");
        player_element.appendChild(captions_container);
        console.log("Captions container added to #player");

        const captions_text_element = captions_container.querySelector(".youtube-full-captions-text");

        resizeObserver = new ResizeObserver(function (entries) {
            for (let entry of entries) {
                adjustFontSize(entry, 3, captions_text_element, 13.71, 27.35);
            }
        });
        resizeObserver.observe(player_element);
        console.log("ResizeObserver set up for captions container");

        const youtube_full_captions_text_element = captions_container.querySelector('.youtube-full-captions-text');

        function copyContents() {
            const visibleCaptions = document.querySelectorAll('.ytp-caption-segment');
            if (visibleCaptions.length > 0) {
                console.log("Captions found on YouTube page");
                const fullCaptionText = Array.from(visibleCaptions).map(cap => cap.textContent).join(' ');
                const words = fullCaptionText.split(' ');

                let currentLine = '';
                youtube_full_captions_text_element.textContent = '';  // Clear previous text
                const containerWidth = youtube_full_captions_text_element.clientWidth;

                words.forEach(word => {
                    const testLine = currentLine + word + ' ';
                    youtube_full_captions_text_element.textContent = testLine;
                    const lineWidth = youtube_full_captions_text_element.scrollWidth;

                    if (lineWidth <= containerWidth) {
                        currentLine = testLine;
                    } else {
                        youtube_full_captions_text_element.textContent += '\n' + word + ' ';
                        currentLine = word + ' ';
                    }
                });

                if (hide_captions_timeout_handle !== null) {
                    clearTimeout(hide_captions_timeout_handle);
                }

                hide_captions_timeout_handle = setTimeout(function () {
                    youtube_full_captions_text_element.style.display = 'none';
                    current_caption = "";
                }, 7000);
            } else if (current_caption !== "") {
                youtube_full_captions_text_element.style.display = 'none';
                current_caption = "";
            }
        }

        const captionWindowObserver = new MutationObserver(copyContents);
        const captionWindow = document.querySelector('.caption-window');
        if (captionWindow) {
            console.log("Setting up MutationObserver for caption window");
            captionWindowObserver.observe(captionWindow, { childList: true, subtree: true });
        }

        setInterval(copyContents, 100);
    } catch (error) {
        console.error("Error in turnOn function:", error);
    }
}

function adjustFontSize(entry, percentage, textElement, minFontSize, maxFontSize) {
    var container = entry.target;
    var containerWidth = container.offsetWidth;
    var fontSize = containerWidth * (percentage / 100);
    fontSize = Math.max(minFontSize, Math.min(fontSize, maxFontSize));
    textElement.style.fontSize = fontSize + 'px';
}

} `

As an example of a video, you can use any and enable automatic translation into another language.

There should be an option whether to turn on automatically on YouTube pages or manually.

My code (written by AI) needs further improvement. It already starts automatically in my language.

Unfortunately, it shows too few words at a time. Hmmm... there should be a slider/window option for how many words at a time it should show. And what to do if it doesn't fit on 1 line - should it show on 2 lines....

Subtitles should be shown slightly in advance of the sound - maybe this could also be set in the options with a slider/value.

Well, and an option for language learners-double subtitles on the screen at once.

(I also have a version that shows the whole sentence, but it reads badly that way-too long a delay).

milenamilka755 commented 1 month ago

New version a little bit better. I managed to display more words in a line, but it's still not what I want, because the words don't appear in advance immediately on line 1....

`if (typeof resizeObserver === 'undefined') { let resizeObserver = null; let hide_captions_timeout_handle = null; let current_caption = ""; const maxWordsPerLine = 12; // Nowy parametr kontrolujący ilość słów na linię

chrome.runtime.onMessage.addListener(
    async function (request, sender, sendResponse) {
        if (request.message === "turnOn") {
            console.log("Turn on message received");
            await turnOn();
        } else if (request.message === "turnOff") {
            location.reload();
        }
    }
);

function waitForElement(selector, timeout = 30000) {
    return new Promise((resolve, reject) => {
        const intervalTime = 100;
        let elapsedTime = 0;

        const interval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                console.log(`Element ${selector} found`);
                clearInterval(interval);
                resolve(element);
            } else if (timeout !== -1 && elapsedTime > timeout) {
                clearInterval(interval);
                reject(new Error(`Element with selector "${selector}" not found within ${timeout}ms`));
            }
            elapsedTime += intervalTime;
        }, intervalTime);
    });
}

async function turnOn() {
    try {
        await waitForElement("button.ytp-subtitles-button", -1);

        const youtube_cc_button_unpressed = document.querySelector('button.ytp-subtitles-button[aria-pressed="false"]');
        if (youtube_cc_button_unpressed !== null) {
            console.log("Turning on YouTube subtitles");
            youtube_cc_button_unpressed.click();
        }

        const captions_container = document.createElement("div");
        captions_container.classList.add("youtube-full-captions-container");
        captions_container.style.position = 'absolute';
        captions_container.style.bottom = '20px';
        captions_container.style.left = '50%';
        captions_container.style.transform = 'translateX(-50%)';
        captions_container.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        captions_container.style.padding = '10px';
        captions_container.style.zIndex = '9999';
        captions_container.innerHTML = "<div class='youtube-full-captions-text' style='color: white;'></div>";

        await waitForElement("#player", -1);
        let player_element = document.querySelector("#player");
        player_element.appendChild(captions_container);
        console.log("Captions container added to #player");

        const captions_text_element = captions_container.querySelector(".youtube-full-captions-text");

        resizeObserver = new ResizeObserver(function (entries) {
            for (let entry of entries) {
                adjustFontSize(entry, 3, captions_text_element, 13.71, 27.35);
            }
        });
        resizeObserver.observe(player_element);
        console.log("ResizeObserver set up for captions container");

        const youtube_full_captions_text_element = captions_container.querySelector('.youtube-full-captions-text');

        function copyContents() {
            const visibleCaptions = document.querySelectorAll('.ytp-caption-segment');
            if (visibleCaptions.length > 0) {
                console.log("Captions found on YouTube page");
                const fullCaptionText = Array.from(visibleCaptions).map(cap => cap.textContent).join(' ');
                const words = fullCaptionText.split(' ');

                youtube_full_captions_text_element.textContent = '';  // Wyczyść poprzedni tekst
                const containerWidth = youtube_full_captions_text_element.clientWidth;

                let currentLine = '';
                let lineCount = 0;

                for (let i = 0; i < words.length; i += maxWordsPerLine) {
                    const lineWords = words.slice(i, i + maxWordsPerLine).join(' ');
                    youtube_full_captions_text_element.textContent = lineWords;

                    if (youtube_full_captions_text_element.scrollWidth > containerWidth && lineCount < 1) {
                        youtube_full_captions_text_element.textContent += '\n' + lineWords;
                        lineCount++;
                    } else {
                        youtube_full_captions_text_element.textContent = lineWords;
                    }
                }

                if (hide_captions_timeout_handle !== null) {
                    clearTimeout(hide_captions_timeout_handle);
                }

                hide_captions_timeout_handle = setTimeout(function () {
                    youtube_full_captions_text_element.style.display = 'none';
                    current_caption = "";
                }, 7000);
            } else if (current_caption !== "") {
                youtube_full_captions_text_element.style.display = 'none';
                current_caption = "";
            }
        }

        const captionWindowObserver = new MutationObserver(copyContents);
        const captionWindow = document.querySelector('.caption-window');
        if (captionWindow) {
            console.log("Setting up MutationObserver for caption window");
            captionWindowObserver.observe(captionWindow, { childList: true, subtree: true });
        }

        setInterval(copyContents, 100);
    } catch (error) {
        console.error("Error in turnOn function:", error);
    }
}

function adjustFontSize(entry, percentage, textElement, minFontSize, maxFontSize) {
    var container = entry.target;
    var containerWidth = container.offsetWidth;
    var fontSize = containerWidth * (percentage / 100);
    fontSize = Math.max(minFontSize, Math.min(fontSize, maxFontSize));
    textElement.style.fontSize = fontSize + 'px';
}

} `