YouTube Audiotrack Reset

Overrides automatic use of generated, translated audiotracks on YouTube videos. Resets to original audio.

// ==UserScript==
// @name            YouTube Audiotrack Reset
// @name:zh-TW      YouTube 音軌重置
// @name:zh-HK      YouTube 音軌重置
// @name:zh-CN      YouTube 音轨重置
// @name:ja         YouTube オーディオトラックリセット
// @name:kr         YouTube 오디오트랙 리셋
// @name:ar         YouTube إعادة تعيين المسار الصوتي
// @name:bg         YouTube Нулиране на аудио пистата
// @name:cs         YouTube Reset audio stopy
// @name:da         YouTube Nulstil lydspor
// @name:de         YouTube Audiotrack zurücksetzen
// @name:tel        YouTube ఆడియో ట్రాక్ రీసెట్
// @name:es         YouTube Restablecer pista de audio
// @name:en         YouTube Audiotrack Reset
// @name:fr         YouTube Réinitialiser la piste audio
// @name:fr-CA      YouTube Réinitialiser la piste audio
// @name:he         YouTube לאפס את מסלול האודיו
// @name:hu         YouTube Audio nyomvonal visszaállítása
// @name:id         YouTube Reset trek audio
// @name:it         YouTube Reimposta traccia audio
// @name:ko         YouTube 오디오 트랙 재설정
// @name:nb         YouTube Tilbakestill lydspor
// @name:nl         YouTube Audiotrack resetten
// @name:pl         YouTube Resetuj ścieżkę audio
// @name:pt-BR      YouTube Resetar trilha de áudio
// @name:ro         YouTube Resetare pistă audio
// @name:ru         YouTube Сброс аудиотрека
// @name:sk         YouTube Obnovenie zvukovej stopy
// @name:sr         YouTube Resetovanje audio trake
// @name:sv         YouTube Återställ ljudspår
// @name:th         YouTube รีเซ็ตแทร็กเสียง
// @name:tr         YouTube Ses parçasını sıfırlama
// @name:uk         YouTube Скинути аудіотрек
// @name:ug         YouTube ئاۋاز يېزىلىشنى قايتا توغرىلاش
// @name:vi         YouTube Đặt lại bản nhạc âm thanh
// @version         0.1.5
// @description     Overrides automatic use of generated, translated audiotracks on YouTube videos. Resets to original audio.
// @description:zh-TW 覆蓋YouTube視頻上自動生成的翻譯音軌。重置為原始音軌。
// @description:zh-HK 覆蓋YouTube視頻上自動生成的翻譯音軌。重置為原始音軌。
// @description:zh-CN 覆盖YouTube视频上自动生成的翻译音轨。重置为原始音轨。
// @description:ja YouTube動画の自動生成された翻訳音声トラックを上書きします。元の音声にリセットします。
// @description:kr YouTube 비디오에서 자동으로 생성된 번역된 오디오 트랙을 덮어씁니다. 원래 오디오로 재설정합니다.
// @description:ar يتجاوز الاستخدام التلقائي للمسارات الصوتية المترجمة المولدة على مقاطع الفيديو الخاصة بـ YouTube. يعيد تعيين الصوت الأصلي.
// @description:bg Пренаписва автоматичното използване на генерирани преведени аудиотреки в YouTube видеа. Нулира до оригиналния звук.
// @description:cs Přepisuje automatické použití generovaných přeložených zvukových stop u videí YouTube. Resetuje na původní zvuk.
// @description:da Omgår automatisk brug af genererede, oversatte lydspor på YouTube-videoer. Nulstiller til original lyd.
// @description:de Überschreibt die automatische Verwendung von generierten, übersetzten Audiotracks in YouTube-Videos. Setzt auf den Originalton zurück.
// @description:tel YouTube వీడియోలపై స్వయంచాలకంగా ఉత్పత్తి చేసిన అనువాద ఆడియో ట్రాక్స్‌ని ఓవర్‌రైడ్ చేస్తుంది. మౌలిక ఆడియోకి రీసెట్ చేస్తుంది.
// @description:es Sobrescribe el uso automático de pistas de audio generadas y traducidas en videos de YouTube. Restablece el audio original.
// @description:en Overrides automatic use of generated, translated audiotracks on YouTube videos. Resets to original audio.
// @description:fr Remplace l'utilisation automatique des pistes audio générées et traduites dans les vidéos YouTube. Réinitialise l'audio original.
// @description:fr-CA Remplace l'utilisation automatique des pistes audio générées et traduites dans les vidéos YouTube. Réinitialise l'audio original.
// @description:he עוקף את השימוש האוטומטי במסלולי אודיו מתורגמים שנוצרו בסרטוני YouTube. מחזיר לאודיו המקורי.
// @description:hu Felülírja a YouTube videók automatikusan generált, lefordított audiótracks használatát. Visszaállítja az eredeti hangot.
// @description:id Menggantikan penggunaan otomatis trek audio terjemahan yang dihasilkan pada video YouTube. Mengatur ulang ke audio asli.
// @description:it Sovrascrive l'uso automatico delle tracce audio tradotte generate nei video di YouTube. Ripristina l'audio originale.
// @description:ko YouTube 비디오에서 자동 생성된 번역된 오디오 트랙의 자동 사용을 덮어씁니다. 원래 오디오로 재설정합니다.
// @description:nb Omgår automatisk bruk av genererte, oversatte lydspor på YouTube-videoer. Tilbakestiller til original lyd.
// @description:nl Overschrijft automatisch gebruik van gegenereerde, vertaalde audiotracks op YouTube-video's. Zet terug naar het originele geluid.
// @description:pl Nadpisuje automatyczne użycie generowanych, przetłumaczonych ścieżek dźwiękowych w filmach YouTube. Resetuje do oryginalnego dźwięku.
// @description:pt-BR Substitui o uso automático de faixas de áudio geradas e traduzidas nos vídeos do YouTube. Restaura para o áudio original.
// @description:ro Suprascrie utilizarea automată a pieselor audio traduse generate pe videoclipurile YouTube. Resetează la audio original.
// @description:ru Перезаписывает автоматическое использование сгенерированных переведенных аудиотреков в видео на YouTube. Возвращает к оригинальному аудио.
// @description:sk Prepisuje automatické použitie generovaných preložených zvukových stôp na videách YouTube. Resetuje na pôvodný zvuk.
// @description:sr Prepisuje automatsko korišćenje generisanih, prevedenih audio traka na YouTube video zapisima. Vraća na originalni zvuk.
// @description:sv Överskriver automatisk användning av genererade översatta ljudspår på YouTube-videor. Återställer till original ljud.
// @description:th แทนที่การใช้แทร็กเสียงที่แปลและสร้างโดยอัตโนมัติในวิดีโอ YouTube รีเซ็ตเป็นเสียงต้นฉบับ
// @description:tr YouTube videolarındaki otomatik olarak oluşturulmuş, çevrilmiş ses izlerinin kullanımını geçersiz kılar. Orijinal sesine sıfırlar.
// @description:uk Перезаписує автоматичне використання згенерованих, переведених аудіотреків на відео YouTube. Скидає до оригінального аудіо.
// @description:ug يۇتۇب ۋىدىئولارىدىكى ئاپتوماتىك تەرجىمە قىلىنغان، ياراتىلغان ئاۋازلارنى ئايرىپ قويىدۇ. ئەسلى ئاۋازغا قايتۇرۇلىدۇ.
// @description:vi Ghi đè việc sử dụng tự động các bản nhạc âm thanh đã được tạo và dịch trên video YouTube. Đặt lại về âm thanh gốc.
// @author          PolyMegos (https://github.com/polymegos)
// @namespace       https://github.com/polymegos/yt-original-audiotrack/
// @supportURL      https://github.com/polymegos/yt-original-audiotrack/issues
// @license         MIT
// @match           *://www.youtube.com/*
// @match           *://www.youtube-nocookie.com/*
// @match           *://m.youtube.com/*
// @match           *://music.youtube.com/*
// @grant           none
// @run-at          document-start
// @compatible      firefox
// @compatible      edge
// @compatible      safari
// ==/UserScript==

(function() {
    'use strict';

    function redirectToDesktop() {
        // Check if we're on m.youtube.com or in a mobile setting
        const isMobile = window.location.hostname === 'm.youtube.com' || 
                                (window.location.hostname === 'www.youtube.com' && 
                                (document.documentElement.classList.contains('mobile')));
        // Look whether desktop param already in URL
        const hasDesktopParam = window.location.search.includes('app=desktop');
        if (isMobile && !hasDesktopParam) {
            // Appending desktop parameter for new URL
            let newUrl = window.location.href;
            if (newUrl.includes('?')) {
                newUrl += '&app=desktop';
            } else {
                newUrl += '?app=desktop';
            }
            // Redirect to desktop version
            console.log('Redirecting to desktop version of YouTube...');
            window.location.href = newUrl;
            return true; // redirect
        }
        return false; // no redirect needed
    }

    // Wait for an element to appear in the DOM
    function waitForElement(selector, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const element = document.querySelector(selector);
            if (element) return resolve(element);
            const observer = new MutationObserver((mutations, obs) => {
                const target = document.querySelector(selector);
                if (target) {
                    obs.disconnect();
                    resolve(target);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
            setTimeout(() => {
                observer.disconnect();
                reject(new Error(`Timeout: Element ${selector} not found within ${timeout}ms`));
            }, timeout);
        });
    }

    // Simulate a click on the given element
    function clickElement(element) {
        if (element) {
            element.click();
        }
    }

    // Wait until no ad shown
    function waitForNoAds(timeout = 10000) {
        return new Promise((resolve, reject) => {
            const player = document.querySelector('.html5-video-player');
            if (!player || !player.classList.contains('ad-showing')) return resolve();
            const observer = new MutationObserver((mutations, obs) => {
                if (!player.classList.contains('ad-showing')) {
                    obs.disconnect();
                    resolve();
                }
            });
            observer.observe(player, { attributes: true, attributeFilter: ['class'] });
            setTimeout(() => {
                observer.disconnect();
                reject(new Error('Timeout: Ad still showing.'));
            }, timeout);
        });
    }

    // Main function to reset the audiotrack
    async function checkAudiotrack() {
        try {
            if (redirectToDesktop()) {
                return; // Early return to redirect to desktop view
            }

            // Wait for the video element and ensure no ad is playing
            await waitForElement('video');
            await waitForNoAds();

            // Open the settings menu
            const settingsButton = await waitForElement('.ytp-settings-button');
            clickElement(settingsButton);
            const settingsMenu = await waitForElement('.ytp-popup.ytp-settings-menu');

            // Find and click the "Audiotrack" item
            const audioTrackItem = Array.from(settingsMenu.querySelectorAll('.ytp-menuitem'))
                .find(item => item.textContent.includes('Audiotrack'));

            if (audioTrackItem) {
                clickElement(audioTrackItem);

                // Wait for the audiotrack submenu to appear
                const audioTrackMenu = await waitForElement('.ytp-popup.ytp-settings-menu');

                // Click the "Original" option
                const originalOption = Array.from(audioTrackMenu.querySelectorAll('.ytp-menuitem'))
                    .find(item => item.textContent.toLowerCase().includes('original'));

                if (originalOption) {
                    clickElement(originalOption);
                } else {
                    console.warn('"Original" audiotrack not found.');
                }
                // Close settings menu
                clickElement(settingsButton);
            } else {
                console.warn('Audiotrack menu not found.');
                // Close half-open settings menu
                clickElement(settingsButton);
            }
        } catch (error) {
            console.error('Error in script:', error);
        }
    }

    // Initial trigger on page load
    checkAudiotrack();

    // Re-run the script after SPA navigation events (when switching videos)
    document.addEventListener('yt-navigate-finish', () => {
        checkAudiotrack();
    });
})();